spring事务
2022-05-03 17:31:28 0 举报
spring事务的整个源码流程图,是要讲事务的切入,事务的传播机制以及事务的提交回滚的流程
作者其他创作
大纲/内容
@EnableTransactionManagement
构造一个TransactionStatus对象(transaction不为空,suspendedResources不为空)
synchronizations也是在这里清掉的
doBegin(真正开启事务啦)
将获得的ConnectionHolder对象通过TransactionSynchronizationManager设置到当前线程的resources这个ThreadLocal中
不会创建事务
抛异常
执行beforeCommit -> beforeCompletion
数据库事务自动提交为falsecon.setAutoCommit(false);
PROPAGATION_NESTED
加了@Transactional注解的类或者类中的方法加了@Transactional注解,那么这个类会生成代理对象作为bean
找事务管理器类型为TransactionManager的Bean对象
a事务和test事务公用一个事务,test()中调用的a(),a方法执行完成后不会去commit,需要等到test执行完后才会去commit
是
isExistingTransaction(transaction)判断当前事务是否开启(是否持有开启的数据库连接对象)
根据回滚标记判断是否要去回滚
status.isNewSynchronization()=true清除当前线程TransactionSynchronizationManager中的ThreadLocal
其他(SUPPORTS、REQUIRED)
触发当前线程中注册的所有TransactionSynchronization的beforeCompletion方法
抛异常(当前线程已经存在事务的情况下,第二个逻辑事务时NEVER则会抛存在事务的异常)
status.isNewTransaction()=true数据库连接重置、关闭
创建一个savepoint(将conn创建的SavePoint设置到TransactionStatus对象中)
这里考虑的是PROXY模式
否
doGetTransaction()方法,拿数据库连接封装到DataSourceTransactionObect对象中并返回该对象
如果有挂起的资源则恢复挂起的资源
try{invocation.proceed}catch{}(执行下一个interceptor或当前被代理对象的方法)
PROPAGATION_NEVER
PROPAGATION_REQUIRES_NEW
new TransactionInfo(将PlatformTransactionManager、TransactionAttribute、DefaultTransactionStatus封装进该对象)
实际就是加入到已存在的那个事务中去运行创建connconn.autoCommit(fasle);target.test()target.a()conn提交回滚
没有
进行回滚,然后执行完finally中的方法后再将异常抛出
执行完finally中的方法然后提交
active synchronization就是在这里执行的,实际就是往synchronizations这个ThreadLocal中添加没有元素的set。我是这么理解synchronizations这个ThreadLocal的:registerSynchronization的时候回去拿到Set列表Set<TransactionSynchronization> synchs = synchronizations.get();然后有个判断:set如果为空的话就是抛错,也就是not active synchronization,也就不能registerSynchronization,程序员就不能监听、spring事务所处的状态。所以synchronizations这个ThreadLocal为啥要active -> registerSynchronization来执行TransactionSynchronization中的beforeCommit()...这些模板方法
挂起当前事务Object suspendedResources = suspend(transaction);
AppConfig这个配置类上配置这个注解,该注解import两个类:AutoProxyRegistrar、ProxyTransactionManagementConfiguration。1.AutoProxyRegistrar:注册一个InfrastructureAdvisorAutoProxyCreator开启自动代理的BeanPostProcessor,这个bean重写了isEligibleAdvisorBean方法,找@Role(BeanDefinition.ROLE_INFRASTRUCTURE)的advisor bean。在bean的初始化后会进入BeanPostProcessor的初始化后方法来判断当前bean是否需要生成代理对象。2.ProxyTransactionManagementConfiguration: - 配置类 - 注册了3个bean 1. BeanFactoryTransactionAttributeSourceAdvisor - pointcut:ClassFilter -> MethodMatcher(先找method有没有@Transactional注解,再找Class有没有@Transactional注解) - advisor.setTransactionAttributeSource(transactionAttributeSource); - advisor.setAdvice(transactionInterceptor); 2. TransactionAttributeSource - 用来解析@Transactional注解的属性封装到RuleBasedTransactionAttribute 3. TransactionInterceptor:就是这里的advisor的advice,事务的代理逻辑就是走的这里。这个advice其实是一个around advice。
DataSourceTransactionObject对象中没有数据库连接则调用DataSource新创建一个数据库连接并设置进该事务对象
1. 恢复挂起的数据库连接2. 恢复TransactionSynchronizationManager中的ThreadLocal3. 恢复挂起的synchronizations,registerSynchronization并执行TransactionSynchronizationd的resume()方法
prepareSynchronization把当前事务的一些信息设置到TransactionSynchronizationManager的各个ThreadLocal中
根据@Transactional注解中的设置,设置DataSourceTransactionObject及Connection对象的隔离级别和readOnly属性
PROPAGATION_MANDATORY
解析@Transactional注解,将属性封装到RuleBasedTransactionAttribute存入以MethodClassKey对象为key的缓存中
startTransaction()真正要去执行开启事务的操作了
TransactionStatus中设置了savepoint
调用conn回滚到上一个savepoint位置
直接回滚conn.rollback()
构造一个TransactionStatus对象(transaction不为空,suspendedResources=null)
触发TransactionSynchronization的afterCompletion方法
拿synchronizations这个ThreadLocal中的数据判断status.isNewSynchronization(),true才会触发
把事务管理器强制转换为PlatformTransactionManager,所以我们在定义bean时得定义PlatformTransactionManager类型
也不会去建立数据库连接
该方法前有个挂起空事务的方法:suspend(null),这个操作没啥意义,线程第一次去开启事务,transaction not active,synchronization not active,就是啥都没做返回null
构造一个TransactionDataStatus对象(transaction=null,suspendedResources不为空)
创建事务,最后事务信息封装到TransactionInfo(每一个逻辑事务都会new一个这个对象,把该对象当作是逻辑事务)
PROPAGATION_NOT_SUPPORTED
执行提交操作,调用数据库连接的提交方法conn.commit();
1. 如果当前数据库连接是新创建的则从resources中清除当前数据库连接2. conn.autoCommit(true); 恢复只读状态和数据库隔离级别3. 如果当前数据库连接是新建的话则关闭当前数据库连接4. 清除ConnectionHolder中的一些数据
status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()这个判断为true的话就会给数据库连接对象设置回滚标记
创建事务逻辑
doBegin子流程(创建conn -> conn.autoCommit(false) -> conn.隔离级别、conn.只读... -> resources添加conn)
得到一个TransactionStatus对象(每个逻辑事务都会new一个这个对象)
在这里其实可以直接拿缓存中的数据,因为再MethodMatcher中进行匹配的时候就会调用getTransactionAttribute方法解析@Transactional注解并存入缓存。缓存为啥能用?缓存是非懒加载单例bean的属性
生成joinpointIdentification(方法全名作为事务名称)
afterCommit
判断当前事务状态TransactionStatus
startTransaction() -> doBegin()去开启一个新事务
进入事务的代理逻辑
封装了@Transactional注解属性对象、用来保存数据库连接的对象(doGetTransaction的时候新new的一个对象)、是否是新事务,是否是新的TransactionSynchronization
当前事务设置已完成的标记TransactionStatus.setCompleted()
getTransaction(TransactionDefiniton)得到TransactionStatus子流程,这里实际就是真正去开启事务的地方(这个子流程比较核心,里面涉及到了传播机制的处理)
PROPAGATION_REQUIRED
执行提交逻辑
其他(NEVER、SUPPORTS、NOT_SUPPORTED)
TransactionSynchronizationManager中包括了很多ThreadLocal,用来记录当前线程中事务的各种信息,比如事务的名字、事务对象、事务的隔离级别等,所以我们也可以通过TransactionSynchronizationManager在业务代码中来获取事务的一些状态
status.isNewTransaction()
将TransactionInfo对象绑定到transactionInfoHolder这个ThreadLocal中,ThreadLocal是TransactionInterceptor这个单例bean的抽象类中的属性,这样就能便于知道current transaction是哪一个。span style=\"font-size: inherit;\
doBegin
判断当前抛出的异常是否需要回滚
判断当前事务的传播机制
代理对象执行有@Transactional注解的方法
有
Participating in larger transaction举例:当前线程第一次开启test事务 -> 第二次开启a事务(SUPPORTED或是REQUIRED),那么a事务会加入到test事务中公用一个test事务
当前事务是新建的事务
执行回滚逻辑
在回滚操作的这个判断本地回滚标记(手动设置了强制回滚)、conn的全局回滚标记(部分失败全局回滚)status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()
判断当前事务的传播机制,处理不同的情况返回TransactionStatus对象
但是传入的事务对象为null(DataSourceTransactionObject)
当前执行的方法,是公用了一个已存在的事务
有没有异常抛出
false
当前线程执行test方法进入代理逻辑第一次去创建事务,拿resources中数据库连接,第一次进来肯定是没有数据的,数据库连接是null,设置到txObject中,此时isExistingTransaction这个判断不成立,那么会去startTranction开启事务...当前线程执行到a()方法第二次去创建事务 -> resources中拿数据库连接(test那个事务中已经创建了)-> new txObject就有数据库连接了,判断也就成立 -> 处理传播机制
cleanupAfterCompletion在finally中的,必然会执行
构造一个TransactionStatus对象(transaction=null,suspendedResources=null)
@Transactional中可以设置哪些异常需要回滚,哪些不需要回滚,默认情况下RuntimeException或Error会回滚
finally中的方法核心就是下面的操作transactionInfoHolder.set(this.oldTransactionInfo);实际就是切换事务a逻辑事务切换到test逻辑事务/** * test * ... * testTransactionInfo.oldTransactionInfo <- null * transactionInfoHolder.set(testTransactionInfo) * ... * a * ... * aTransactionInfo.oldTransactionInfo <- testTransactionInfo * transactionInfoHolder.set(aTransactionInfo) * */
true
0 条评论
下一页