动态代理和@transactional事务传递简单理解

事务的传递:总结,无论怎样,调用一个类的第一个方法要加注解。第二个可以不用加。否则就是无效的。

动态代理简述:有两种实现方式,一是jdk反射机制代理,二是CGLIB增强代理。
这里只简述jdk反射机制的使用步骤:新建接口,新建接口的实现类,并编写具体实现内容,新建处理器类实现InvocationHandler,实现invoke方法,可以在其中写切面内容。然后使用时,调用Proxy.newProxyInstance方法,三个参数分别是,要代理的目标类的加载器,目标类实现的所有接口,处理器类。最后调用切点方法。

spring使用@Transactional事务传递时,假如说controller调用service中的方法A,注意这个调用过程是通过前面说的处理器调用的,a没有@Transactional这个注解,那么在走这个处理器的时候会先判断是否有这个注解,如果没有就不会走这个切点的切面方法,所以也就不会开启事务。接着在a方法里面有调用b方法,b方法有@Transactional注解,但是这个调用属于方法间的调用,不走代理,所以此时的注解并没有起作用,也就不会开启事务。
如果控制层直接调用service的b方法,那么是可以事务的。

如果先调用b方法,再调用a方法,无论a是否带@transactional注解,都会在b的事务中。因为了解aop的都知道,方法的实体是在前置后置之间执行的就如同事务前后的开启和关闭。

为什么呢?因为service层注入到控制层,对象是交给spring容器管理的,这就涉及到了spring三级缓存了,三级缓存中第三级存放的是aop代理对象。当控制层调用注入到自己类中的业务层方法时,是通过代理的,而在这个代理过程中,会有一个判断,判断该方法是否有@transactional注解,有就走带事务的语句,没有就直接执行sql.

解决办法,明白原理了,那么解决办法就是
1:把注解加到整个类上,这样就保证了任何一个方法都是通过代理调用的。
2在当前类中注入当前类,然后.方法去调用。或者是把方法放到别的bean中,注入进来,再.方法调用。

注解的作用:比如这里的@transactional注解作用就是通过所在方法是否有这个注解来判断的。如果这个注解中有方法就扩大了判断范围,比如@transactional提供的七个事务传递参数,也是通过判断走对应流程的

<think>好的,我现在需要理解Spring的@Transactional注解是如何实现的,以及它的底层逻辑。首先,我应该回顾一下自己对这个主题已有的了解,然后逐步深入分析可能涉及的机制。 我记得Spring框架中的事务管理是通过@Transactional注解来实现声明式事务的。这种声明式事务管理是基于AOP(面向切面编程)的,可能使用了代理模式。当我们在方法或类上添加@Transactional注解时,Spring会为该类生成代理,以便在方法执行前后管理事务的开启、提交或回滚。 但是具体是如何生成代理的呢?这里可能涉及到Spring AOP动态代理。如果是接口,可能使用JDK动态代理;如果是具体类,可能使用CGLIB来生成子类代理。代理对象会拦截带有@Transactional注解的方法,并在方法执行前后加入事务管理的逻辑。 接下来,事务管理器的角色是什么?我记得Spring的事务管理抽象是基于PlatformTransactionManager接口的,具体实现比如DataSourceTransactionManager用于JDBC事务,HibernateTransactionManager用于Hibernate等。事务管理器负责实际的事务操作,如开始事务、提交回滚。 那么,事务的传播行为是如何处理的?比如,PROPAGATION_REQUIRED表示如果当前存在事务,就加入该事务,否则新建一个。这些传播行为应该是在事务管理器中实现的,根据当前线程上下文中的事务状态来决定如何处理。 另外,@Transactional注解的属性,比如隔离级别、回滚条件等,应该在生成事务时被读取并设置到事务属性中。例如,当方法抛出异常时,会根据rollbackFor指定的异常类型决定是否回滚事务。 这里可能还涉及到事务同步线程绑定的资源,比如数据库连接。在事务开始时,Spring可能会从数据源获取连接,并将其绑定到当前线程,这样在同一个事务中的多个数据库操作会使用同一个连接,保证事务的一致性。 但是,当使用@Transactional时,如果方法内部调用了同一个类中的其他方法,会不会导致事务失效?这可能是因为自调用时,代理对象的方法没有被调用,而是直接调用了目标对象的方法,绕过了代理,导致事务通知没有被应用。这种情况下,可能需要通过AopContext.currentProxy()来获取代理对象,或者将方法移到另一个Bean中。 还有,事务的提交回滚是如何触发的?在方法执行完成后,如果没有异常抛出,代理会提交事务;如果抛出了适当的异常,则会回滚。这里可能有一个异常处理机制,检查抛出的异常是否匹配rollbackFor或noRollbackFor指定的类型。 底层实现的关键点可能包括: 1. 代理机制的创建:Spring容器在创建Bean时,检测到@Transactional注解,会通过BeanPostProcessor处理,生成代理对象。 2. 事务拦截器:使用TransactionInterceptor作为方法拦截器,在方法执行前后处理事务。 3. 事务管理器与事务同步:事务的实际操作由PlatformTransactionManager处理,结合线程本地存储来管理事务上下文。 4. 事务属性的解析:从@Transactional注解中提取属性,如传播行为、隔离级别等,转化为TransactionAttribute。 可能需要查阅Spring的源码来确认这些机制。例如,TransactionInterceptor的invoke方法会调用PlatformTransactionManager的相关方法,根据传播行为决定事务的创建、挂起或加入。同时,异常处理时会触发回滚条件检查。 总结来说,@Transactional的实现依赖于Spring AOP生成代理,拦截方法调用,通过事务管理器处理事务的生命周期,并结合线程上下文来维护事务状态。具体的传播行为属性设置则是在事务管理器中根据注解属性来决定的。</think>Spring 的 `@Transactional` 注解通过 **声明式事务管理** 实现,其底层逻辑基于 **AOP(面向切面编程)** **代理模式**,结合事务管理器(`PlatformTransactionManager`)完成事务的创建、提交或回滚。以下是其核心实现机制: --- ### 一、核心实现步骤 1. **代理对象的生成** - 当 Spring 容器检测到 Bean 类或方法上有 `@Transactional` 注解时,会通过 `BeanPostProcessor`(如 `AbstractAutoProxyCreator`)为该 Bean 创建代理对象。 - **动态代理类型**: - 若目标类实现了接口,默认使用 **JDK 动态代理**。 - 若无接口,使用 **CGLIB** 生成子类代理。 2. **事务拦截器(TransactionInterceptor)** - 代理对象会拦截带有 `@Transactional` 的方法调用。 - `TransactionInterceptor` 负责事务的开启、提交或回滚,核心逻辑在 `invoke()` 方法中: ```java public Object invoke(MethodInvocation invocation) throws Throwable { // 1. 获取事务属性(如传播行为、隔离级别) TransactionAttribute txAttr = determineTransactionAttribute(invocation.getMethod()); // 2. 获取事务管理器(PlatformTransactionManager) PlatformTransactionManager tm = determineTransactionManager(); // 3. 根据传播行为处理事务(如新建、加入已有事务) TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, invocation.getMethod(), invocation.getArguments()); Object retVal; try { // 4. 执行目标方法 retVal = invocation.proceed(); } catch (Throwable ex) { // 5. 异常处理:决定是否回滚 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } // 6. 提交事务 commitTransactionAfterReturning(txInfo); return retVal; } ``` 3. **事务管理器(PlatformTransactionManager)** - 具体事务操作(如开始、提交、回滚)由 `PlatformTransactionManager` 实现类处理(如 `DataSourceTransactionManager` 用于 JDBC)。 - 事务管理器通过 **线程本地存储(ThreadLocal)** 维护当前事务的上下文(如数据库连接),确保同一事务中的操作共享资源。 --- ### 二、关键底层逻辑 1. **事务传播行为** - 传播行为(如 `PROPAGATION_REQUIRED`)决定了事务如何与现有事务交互。例如: - `PROPAGATION_REQUIRED`:若当前存在事务,则加入;否则新建事务。 - `PROPAGATION_REQUIRES_NEW`:挂起当前事务,新建独立事务。 - 通过 `TransactionStatus` `TransactionDefinition` 实现事务的挂起与恢复。 2. **事务的隔离级别与超时** - 从 `@Transactional` 注解中解析隔离级别(`isolation`)、超时时间(`timeout`)等属性,传递事务管理器。 3. **异常回滚机制** - 默认情况下,仅对 `RuntimeException` `Error` 回滚。 - 可通过 `rollbackFor`/`noRollbackFor` 自定义回滚条件。若方法抛出指定异常,事务会回滚。 4. **资源绑定与同步** - 事务开启时,数据库连接会被绑定到当前线程(通过 `TransactionSynchronizationManager`)。 - 同一事务中的多个操作共享该连接,确保原子性。 --- ### 三、常见问题与注意事项 1. **自调用失效** - 若类内部方法 A 调用带有 `@Transactional` 的方法 B,事务可能不生效(因直接调用目标对象而非代理对象)。 - **解决方案**:通过 `AopContext.currentProxy()` 获取代理对象,或使用 AspectJ 编译时织入。 2. **事务传播的嵌套** - 嵌套事务需注意传播行为配置。例如,`PROPAGATION_REQUIRES_NEW` 会创建独立事务,外层事务回滚不影响内层。 3. **只读事务优化** - 若标记为 `readOnly = true`,某些数据库或 ORM 框架会进行优化(如跳过写锁)。 --- ### 四、总结 `@Transactional` 的实现本质是 **AOP 代理 + 事务管理器协作**: 1. **代理层** 拦截方法调用,管理事务边界。 2. **事务管理器** 处理具体事务操作(如 JDBC/Hibernate 事务)。 3. **线程本地存储** 维护事务上下文,确保资源一致性。 通过合理配置传播行为、隔离级别异常回滚规则,可灵活控制事务的粒度与行为。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老马识途2.0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值