面试官:问你一个,Spring事务是如何传播的?
推荐学习
- 肝了十天半月 , 献上纯手绘“Spring/Cloud/Boot/MVC”全家桶脑图
- 疯狂膜拜!阿里出品Spring Security王者晋级文档
- 真香警告!Alibaba珍藏版mybatis手写文档 , 刷起来
文章插图
前言Spring事务是如何传播的?
其实之前有分析事务注解的解析过程 , 本质上是将事务封装为切面加入到AOP的执行链中 , 因此会调用到MethodInceptor的实现类的invoke方法 , 而事务切面的Interceptor就是TransactionInterceptor , 所以本篇直接从该类开始 。
事务切面的调用过程
public Object invoke(MethodInvocation invocation) throws Throwable {// Work out the target class: may be {@code null}.// The TransactionAttributeSource should be passed the target class// as well as the method, which may be from an interface.Class> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);// Adapt to TransactionAspectSupport's invokeWithinTransaction...return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed); }
这个方法本身没做什么事 , 主要是调用了父类的invokeWithinTransaction方法 , 注意最后一个参数 , 传入的是一个lambda表达式 , 而这个表达式中的调用的方法应该不陌生 , 在分析AOP调用链时 , 就是通过这个方法传递到下一个切面或是调用被代理实例的方法 , 忘记了的可以回去看看 。 protected Object invokeWithinTransaction(Method method, @Nullable Class> targetClass,final InvocationCallback invocation) throws Throwable {// If the transaction attribute is null, the method is non-transactional.//获取事务属性类 AnnotationTransactionAttributeSourceTransactionAttributeSource tas = getTransactionAttributeSource();//获取方法上面有@Transactional注解的属性final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);//获取事务管理器final PlatformTransactionManager tm = determineTransactionManager(txAttr);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal = null;try {// 调用proceed方法retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {// target invocation exception//事务回滚completeTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}//事务提交commitTransactionAfterReturning(txInfo);return retVal;}// 省略了else }
这个方法逻辑很清晰 , 一目了然 , if里面就是对声明式事务的处理 , 先调用createTransactionIfNecessary方法开启事务 , 然后通过invocation.proceedWithInvocation调用下一个切面 , 如果没有其它切面了 , 就是调用被代理类的方法 , 出现异常就回滚 , 否则提交事务 , 这就是Spring事务切面的执行过程 。 但是 , 我们主要要搞懂的就是在这些方法中是如何管理事务以及事务在多个方法之间是如何传播的 。事务的传播性概念传播性是Spring自己搞出来的 , 数据库是没有的 , 因为涉及到方法间的调用 , 那么必然就需要考虑事务在这些方法之间如何流转 , 所以Spring提供了7个传播属性供选择 , 可以将其看成两大类 , 即是否支持当前事务:
- 支持当前事务(在同一个事务中):
- 不支持当前事务(不在同一个事务中):
别看属性这么多 , 实际上我们主要用的是PROPAGATION_REQUIRED默认属性 , 一些特殊业务下可能会用到PROPAGATION_REQUIRES_NEW以及PROPAGATION_NESTED 。 下面我会假设一个场景 , 并主要分析这三个属性 。
public class A {@Autowired private B b; @Transactional public void addA() {b.addB(); }}public class B { @Transactional public void addB() {// doSomething... }}
- 蛋壳公寓|官媒发声:绝不能让“割韭菜者”一跑了之!
- 表达|重磅!2021世界安防博览会官方宣贯会正式召开,百余家企业表达参展意愿
- 公司|LVMH首席数字官跳槽至加密数字钱包公司Ledger
- 成为佛山移动服务体验官 表白留言赢取百元话费
- Store|在BlueMail的App Store反垄断案中 法官作出有利于苹果公司的判决
- 正式|首批体验官正式招募!仰望高端定制,OriginOS玩法大搜罗
- 全新|首批支持5款机型,vivo开启OriginOS首批体验官招募
- 全新|OriginOS招募首批体验官,网友:先冲为敬
- 无人|无人维护?官方打脸:Element UI for Vue 3.0 来了!
- 代言人|OPPO官宣“周冬雨”成为新代言人,周冬雨排列难道会被用上?