一、Spring事务底层支持
如果需要开启Spring支持数据库事务,只需要使用@EnableTransactionManagement。
开启Spring事务本质:向Spring容器增加一个Advisor。
EnableTransactionManagement注解原理
利用TransactionManagementConfigurationSelector类向Spring容器中添加了两个Bean。
1. AutoProxyRegistrar
2. ProxyTransactionManagementConfiguration
AutoProxyRegistrar
向Spring容器中注册一个继承了AbstractAdvisorAutoProxyCreator的InfrastructureAdvisorAutoProxyCreator的Bean。
InfrastructureAdvisorAutoProxyCreator类的主要作用就是开启自动代理,本质是一个BeanPostProcessor,会在初始化后步骤中去寻找Advisor类型的Bean,并判断当前某个Bean是否有匹配的Advisor,是否需要利用动态代理产生一个代理对象。
ProxyTransactionManagementConfiguration
本质是一个配置类,定义另外三个bean
1. BeanFactoryTransactionAttributeSourceAdvisor:一个Advisor
2. AnnotationTransactionAttributeSource:相当于BeanFactoryTransactionAttributeSourceAdvisor中的Pointcut。用于**判断类或者方法上是否存在@Transactional注解,并进行解析注解**
3. TransactionInterceptor:相当于BeanFactoryTransactionAttributeSourceAdvisor中的Advice。事务代理逻辑。被@Transactional注解标记时,会产生一个代理对象,代理对象执行标记的方法是,会进入TransactionInterceptor的invoke()方法。
二、Spring事务基本执行原理
在Spring生命周期中,每一个Bean会在初始化后步骤中,经过InfrastructureAdvisorAutoProxyCreator处理(判断当前Bean对象是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,即:判断Bean对应类或者方法上是否被@Transactional注解标记。如果被标记,则会进行动态代理,产生一个代理对象)
因为被@Transactional注解标记,而产生的代理对象在执行某个方法时,会再次判断当前执行的方法是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,如果匹配则执行该Advisor中的TransactionInterceptor的invoke()方法(AOP的标准两次判断。生成代理对象时判断,具体执行时判断)
基本执行流程
- 利用所配置的PlatformTransactionManager事务管理器新建一个数据库连接
- 修改数据库连接的autocommit为false
- 执行MethodInvocation.proceed()方法,即执行业务方法中的sql
- 如果没有抛异常,则提交
- 如果抛了异常,则回滚
三、Spring事务传播机制
默认情况下传播机制为REQUIRED,表示当前如果没有事务则新建一个事务,如果有事务则在当前事务中执行。
分析REQUIRED_NEW。创建一个新的事务,挂起当前事务
- 代理对象执行insert()方法前,先利用事务管理器新建一个数据库连接conn1
- 将数据库连接conn1的autocommit改为false
- 把数据库连接conn1设置到ThreadLocal中
- 执行target.insert()方法中的sql
- 执行insert()方法过程中,调用了update()方法(注意用代理对象调用update()方法)
- 代理对象执行update()方法前,判断当前线程中已经存在一个数据库连接conn1了,表示当前线程其实已经拥有一个Spring事务,则进行挂起当前数据库连接
- 挂起,就是把ThreadLocal中的数据库连接conn1,从ThreadLocal中移除,并放入一个挂起资源对象中
- 挂起完成后,再次利用事务管理器新建一个数据库连接conn2
- 将数据库连接conn2的autocommit改为false
- 把数据库连接conn2设置到ThreadLocal中
- 执行update()方法中的sql
- update()方法正常执行完,则从ThreadLocal中拿到数据库连接conn2进行提交
- 提交之后会恢复所挂起的数据库连接conn1,这里的恢复,其实只是把在挂起资源对象中所保存的数据库连接conn1再次设置到ThreadLocal中
- insert()方法正常执行完,则从ThreadLocal中拿到数据库连接conn1进行提交
最核心的是:在执行某个方法时,判断当前是否已经存在一个事务,就是判断当前线程的ThreadLocal中是否存在一个数据库连接对象,如果存在则表示已经存在一个事务。
传播行为 | 描述 | |
---|---|---|
PROPAGATION_REQUIRED | 默认传播级别,若当前存在事务,则加入该事务,若不存在事务,则新建一个事务 | |
PROPAGATION_REQUIRE_NEW | 若当前没有事务,则新建一个事务。若当前存在事务,则新建 一个事务,挂起当前事务。新老事务相互独立。外部事务抛出异常回滚不会影响内部事务的正常提交 | |
PROPAGATION_NESTED | 如果当前存在事务,则嵌套在当前事务中执行。如果当前没有事务, 则新建一个事务,类似于REQUIRE_NEW | |
PROPAGATION_SUPPORTS | 支持当前事务,若当前不存在事务,以非事务的方式执行 | |
PROPAGATION_NOT_SUPPORTED | 以非事务的方式执行,若当前存在事务,则把当前事务挂起 | |
PROPAGATION_MANDATORY | 强制事务执行,若当前不存在事务,则抛出异常 | |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常 |