Spring事务的实现原理(@Transactional原理 + 失效场景)

本文深入解析Spring事务管理,包括编程式和声明式事务配置,重点介绍了@Transactional的实现原理,如启用事务管理、事务传播行为以及事务失效场景。通过理解这些概念,你将能够更好地掌握Spring框架的事务控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果你正打算深入学习Spring,但是不知从何学起,那么我强烈推荐你可以按照这个系列做一遍。本系列将Spring框架的各个部分从它庞杂的代码体系中抽取出来,然后对每一个部分进行讲解,并最终搭建成简易版Spring。我以人格保证:如果你可以坚持做下来,那么你对Spring这块的知识就基本都掌握清楚了! 附上该系列地址:https://blog.youkuaiyun.com/zhang_qing_yun/article/details/120084497

Spring事务管理

Spring事务的配置方式

Spring支持两种事务配置方式:

  1. 编程式事务配置:使用TransactionTemplate(推荐)或者直接使用PlatformTransactionManager通过硬编码的方式在业务代码中来管理事务。
  2. 声明式事务配置:通过XML配置或者注解的方式来声明开启事务,然后让Spring来接管事务的实现逻辑,通过这种方式,我们只需要声明事务而不用去管理事务。声明式事务管理建立在AOP之上,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。

对比:编程式事务是侵入式的,对业务代码的编写有影响,并且每次使用都需要单独实现,非常繁琐;声明式事务属于无侵入式,不会影响业务逻辑的实现,只需要通过配置文件或者注解的方式声明事务便可以将事务规则应用到业务逻辑中。但是,声明式事务管理的粒度是方法级别,而编程式事务管理是可以到代码块的。

Spring的事务传播

首先,事务传播都是在一个线程内完成的;其次,所谓的事务传播行为是相对于内层被调用函数来说的,Spring提供了7种事务传播机制:

事务传播机制

@Transactional的实现原理

首先我们需要在主配置类上添加@EnableTransactionManagement注解来开启事务,这个注解通过@Import注解向容器中引入了两个类:AutoProxyRegistrar和ProxyTransactionManagementConfiguration。

AutoProxyRegistrar向容器中导入了InfrastructureAdvisorAutoProxyCreator,该类继承于AbstractAutoProxyCreator,作用类似于AOP,只不过是用于为加了@Transactional注解的类生成代理对象。

ProxyTransactionManagementConfiguration向容器中导入了3个Bean:AnnotationTransactionAttributeSource、TransactionInterceptor、BeanFactoryTransactionAttributeSourceAdvisor,其中前两个都是第三个的属性,而第三个是一个Advisor,前两者一个相当于切点,用于判断是否加了@Transactional注解,另一个是一个拦截器,具体事务管理的逻辑就是在该拦截器的invoke()方法中实现的。

整体的执行流程:当创建一个Bean时,会去执行AbstractAutoProxyCreator的postProcessAfterInitialization,在这个方法中会去判断是否需要为该Bean生成代理对象。这时会去获取所有的Advisor,然后遍历并从中找出与该Bean相匹配的,此时就会用BeanFactoryTransactionAttributeSourceAdvisor的属性AnnotationTransactionAttributeSource去对该Bean进行判断,如果该Bean或它的方法加了@Transactional注解则匹配成功(注意:非public方法加了该注解也没用,不匹配),将该BeanFactoryTransactionAttributeSourceAdvisor返回。由于返回值不为空,所以就会为该Bean创建代理对象。

当调用该代理对象的方法时,会先去获取该方法的拦截器链(遍历该Bean的所有Advisor,然后找到和该方法相匹配的Advisor)。BeanFactoryTransactionAttributeSourceAdvisor的属性AnnotationTransactionAttributeSource会去判断该方法是否有@Transactional注解,如果有则匹配成功,则将该Advisor的属性TransactionInterceptor添加到拦截器链中。然后从头开始遍历拦截器链(通过递归调用proceed()方法完成遍历),当执行TransactionInterceptor的invoke()方法时,会先去开启一个事务,然后再去递归调用proceed()方法向下遍历,直至执行完业务方法,如果在这个过程中出现了异常就回滚事务,否则就提交事务。

在整个事务过程中,如何保证操作数据库时使用的是同一个连接?在开启事务时,首先会从数据库连接池中获得一个connection,然后将这个连接与一个ThradLocal对象绑定起来,以后需要操作数据库时都通过该ThradLocal对象来获取connection,最后在事务提交或回滚后释放绑定关系,并将connection归还到数据库连接池中。这样,通过ThradLocal对象,我们就保证了操作的是同一个connection。(ThradLocal相关知识移步:https://blog.youkuaiyun.com/zhang_qing_yun/article/details/118884946

在这里插入图片描述

@Transactional失效的场景

  1. 非public的方法。原因就是在为该Bean寻找匹配的Advisor时,如果是非public方法加了该注解会忽视掉。
  2. 使用final修饰的方法在使用CGLIB动态代理时。原因就是CGLIB并不会代理final方法。
  3. 类内部的非事务方法调用事务方法。原因就是,事务方法的调用是通过this来完成的,跳过了代理对象。
  4. 自己捕获了异常。原因就是没有抛出新的异常,导致事务操作不会进行回滚。

具体可以参考:https://blog.youkuaiyun.com/qq_20597727/article/details/84900994

<think>好的,我需要回答用户关于Spring Boot中@Transactional注解实现原理的问题。首先,用户提到了AOP和代理机制,所以我需要先回忆相关知识。 首先,Spring事务管理是通过@Transactional注解来实现的,这点用户已经知道。根据引用[1],Spring Boot自动配置了DataSourceTransactionManager,当使用MyBatis时,Spring Boot会自动处理事务管理器。所以基础的事务管理是Spring Boot自动配置的,用户只需要添加注解即可。 接下来,用户想知道实现机制,特别是AOP和代理的部分。引用[2]提到,Spring事务基于AOP,只有通过代理对象调用方法时事务才生效。自调用会失败,因为this指向的不是代理对象。这说明Spring使用代理来包裹被注解的方法,在方法调用前后添加事务管理的逻辑。 那具体的实现步骤应该是怎样的呢?首先,当应用启动时,Spring会扫描带有@Transactional注解的类或方法。然后,通过AOP创建代理对象。这个代理对象可能是JDK动态代理(针对接口)或CGLIB代理(针对类)。代理对象会在目标方法执行前开启事务,在方法执行后根据情况提交或回滚事务。 另外,需要提到事务的传播机制和隔离级别,这些是通过注解的参数来配置的。例如,Propagation.REQUIRED表示如果当前存在事务,就加入该事务,否则新建一个。这些设置会影响代理对象如何处理事务边界。 还要注意,自调用的问题,因为同一个类中的方法调用不会经过代理,所以事务不会生效。这一点需要特别说明,可能用户在使用时需要注意避免这种情况,或者通过其他方式解决,比如注入自身的代理实例。 总结一下,回答的结构应该是:1. 注解触发事务管理器的自动配置;2. AOP创建代理对象;3. 代理对象管理事务的开启、提交和回滚;4. 传播机制和隔离级别的处理;5. 自调用问题的解释。同时,需要引用用户提供的引用内容来支持这些点,比如引用[1]和[2]。 现在需要检查是否有遗漏的部分,比如事务同步、事务拦截器TransactionInterceptor的作用,以及Spring如何处理多个事务管理器的情况。不过用户的问题主要集中在实现机制和AOP代理上,可能不需要深入太多细节,但应该提到关键组件如TransactionInterceptor。 最后,生成相关问题时要围绕事务实现、AOP、代理、常见问题等方面。例如,事务失效场景、如何选择代理方式、传播机制的不同行为等。</think>### Spring Boot中@Transactional注解的实现原理 Spring Boot通过`@Transactional`注解实现声明式事务管理,其核心机制基于**AOP(面向切面编程)**和**动态代理**技术。以下是具体实现步骤: --- #### 1. **事务管理器的自动配置** 当项目引入Spring Boot的事务模块(如`spring-boot-starter-jdbc`或`spring-boot-starter-data-jpa`)时,Spring Boot会自动配置`PlatformTransactionManager`实现类(如`DataSourceTransactionManager`)。这是事务操作的基础组件[^1]。 --- #### 2. **AOP代理的创建** - **代理对象生成**:Spring通过AOP为标注`@Transactional`的类或方法创建代理对象。代理方式包括: - **JDK动态代理**:若目标类实现了接口,默认使用JDK代理。 - **CGLIB代理**:若目标类未实现接口,则使用CGLIB生成子类代理。 - **切面逻辑注入**:代理对象会在目标方法执行前后插入事务管理逻辑,例如开启事务、提交或回滚事务。 --- #### 3. **事务拦截器(TransactionInterceptor)** 代理对象通过`TransactionInterceptor`拦截方法调用,具体流程如下: 1. **开启事务**:根据注解配置(如传播行为、隔离级别)获取或创建事务。 2. **执行目标方法**:调用原始方法。 3. **提交或回滚**:根据方法执行结果(是否抛出异常)决定提交或回滚事务。 ```java // 伪代码示例:事务拦截逻辑 public Object invoke(MethodInvocation invocation) { TransactionStatus status = beginTransaction(); try { Object result = invocation.proceed(); // 执行目标方法 commitTransaction(status); return result; } catch (Exception e) { rollbackTransaction(status); throw e; } } ``` --- #### 4. **事务传播机制的处理** `@Transactional`的传播行为(如`Propagation.REQUIRED`)通过事务管理器协调多事务的嵌套或合并。例如: - **REQUIRED**:若当前存在事务,则加入;否则新建事务。 - **REQUIRES_NEW**:始终新建独立事务,挂起当前事务(若存在)。 --- #### 5. **自调用问题的根源** 在类内部方法A调用方法B(两者均有`@Transactional`),由于`this`指向原始对象而非代理对象,事务逻辑不会触发[^2]。解决方法包括: - 通过`AopContext.currentProxy()`获取代理对象。 - 将事务方法拆分到其他类中。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值