事务源码(一)
Spring 的源码一般从@EnableXX 开始看,然后会导入@Enable 一般通过@Import 导入一些相关的配置类。
0. 前沿
ACID Atomicity Consistency Isolation Durabiliry
- 原子性 事务要么全做要么不做
- 一致性 事务前后的状态是一致的,不会造成数据不一致的状态
- 隔离性 多个事务直接互相不影响
- 永久性 一个事务commit 之后对数据的影响是永久性的
脏读: 事务A读取到事务B未提交的数据
不可重复度: 事务A两次读取同一条数据内容不一致,也就是读到了其他事务修改掉的数据
幻读/虚读: 两次读取到的数据量不一致
关于隔离级别与事务问题对应关系如下:
对于Mysql 来说,RR 隔离级别也不存在虚读的问题,也就是Mysql 事务读取不到其他事务新增加的数据。 采用多版本并发控制(MVCC)机制解决幻读问题 。
测试:
表结构:
CREATE TABLE `account` ( `id` int(11) NOT NULL AUTO_INCREMENT, `accountName` varchar(20) DEFAULT NULL, `user` varchar(20) DEFAULT NULL, `money` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
1. 脏读问题测试:
(1) session1:
SET tx_isolation = 'read-uncommitted'; BEGIN; INSERT INTO account(accountName, USER, money) VALUES('zs', 'zs', 100) ROLLBACK; COMMIT;
(2) session2
SET tx_isolation = 'read-uncommitted'; SELECT * FROM account;
结果: session2 会读到未提交的数据
2. 不可重复读: 两次读到的数据内容不一致
插入一条数据:
(1) session1 执行如下:
SET tx_isolation = 'read-committed'; BEGIN; select * from account; # 做其他操作 select * from account; COMMIT;
(2) session2 如下:
SET tx_isolation = 'read-committed'; BEGIN; update account set money = money + 1; COMMIT;
测试:
- session1 先执行第一次select,结果如下:
- session2 进行update:
- session1 第二次进行select, 结果如下: (一次事务多次读取数据内容不一致)
3. 幻读: 同一个事务两次读到的数据量不一致
(1) session1
SET tx_isolation = 'repeatable-read'; BEGIN; select * from account; # 另外一条事务插入数据 select * from account; insert into account(accountName, user, money) values('zs', 'zs', 100) select * from account; update account set money = money + 1 where user = 'zs'; select * from account; update account set money = money + 1 where user = 'wangwu'; select * from account; COMMIT;
(2) session2:
SET tx_isolation = 'repeatable-read'; BEGIN; insert into account(accountName, user, money) values('wangwu', 'wangwu', 100); commit;
测试:
(1) 确保数据库只有一条数据: 新开事务插入一条数据
truncate table account; insert into account(accountName, user, money) values('lisi', 'lisi', 100); select * from account;
(2) 执行session1 第一次查询语句之前的开启事务以及查询语句:
(3) 执行session2 的insert 操作,并且提交
(4) 新事务查询
(5) 执行session1 第二次查询语句:
(6) 执行session1 的insert 操作
(7) 再次执行session1 的第三次查询
(8) 执行session1 的修改操作
(9) 再次执行session1 的查询操作
(10) 执行session1 的第二次 修改
(11) 最后再次查询, 发现数据多出来一条
可以看出,update 是采用的当前读,虽然当前事务没有查到相关数据,但是update 也会成功,并且update 之后会将update 的数据加入当前事务。
1. 配置类解读
事务的入口: org.springframework.transaction.annotation.EnableTransactionManagement
package org.springframework.transaction.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.AdviceMode; import org.springframework.context.annotation.Import; import org.springframework.core.Ordered; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(TransactionManagementConfigurationSelector.class) public @interface EnableTransactionManagement { boolean proxyTargetClass() default false; AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE; }
通过@Import 引入了TransactionManagementConfigurationSelector
package org.springframework.transaction.annotation; import org.springframework.context.annotation.AdviceMode; import org.springframework.context.annotation.AdviceModeImportSelector; import org.springframework.context.annotation.AutoProxyRegistrar; import org.springframework.transaction.config.TransactionManagementConfigUtils; import org.springframework.util.ClassUtils;
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] {determineTransactionAspectClass()}; default: return null; } } private String determineTransactionAspectClass() { return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ? TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME : TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME); } }
这里会注入ProxyTransactionManagementConfiguration,自动配置类:org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration, 这个类注入了几个重要的事务相关bean
package org.springframework.transaction.annotation; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Role; import org.springframework.transaction.config.TransactionManagementConfigUtils; import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor; import org.springframework.transaction.interceptor.TransactionAttributeSource; import org.springframework.transaction.interceptor.TransactionInterceptor; @Configuration(proxyBeanMethods = false) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor( TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) { BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor(); advisor.setTransactionAttributeSource(transactionAttributeSource); advisor.setAdvice(transactionInterceptor); if (this.enableTx != null) { advisor.setOrder(this.enableTx.<Integer>getNumber("order")); } return advisor; } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource() { return new AnnotationTransactionAttributeSource(); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) { TransactionInterceptor interceptor = new TransactionInterceptor(); interceptor.setTransactionAttributeSource(transactionAttributeSource); if (this.txManager != null) { interceptor.setTransactionManager(this.txManager); } return interceptor; } }
(1) org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration 事务自动配置的相关类
(2) org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor 可以理解为切面Aspect的角色(内部维护Point与Advisor)
(3) org.springframework.transaction.interceptor.TransactionAttributeSource 用于获取TransactionAttribute 事务属性,也就是读取@Transactional 注解上的相关属性
(4) org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#TransactionAttributeSourcePointcut (是否需要进行事务的控制是在这个类进行判断的)
(5) org.springframework.transaction.interceptor.TransactionInterceptor 事务拦截器。 (对事务的处理是在这个类)
2. 分析过程
事务的拦截器入口: org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor, 源码如下:
package org.springframework.transaction.interceptor; import org.springframework.aop.ClassFilter; import org.springframework.aop.Pointcut; import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor; import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { @Nullable private TransactionAttributeSource transactionAttributeSource; private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { @Override @Nullable protected TransactionAttributeSource getTransactionAttributeSource() { return transactionAttributeSource; } }; public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) { this.transactionAttributeSource = transactionAttributeSource; } public void setClassFilter(ClassFilter classFilter) { this.pointcut.setClassFilter(classFilter); } @Override public Pointcut getPointcut() { return this.pointcut; } }
TransactionAttributeSource:上面配置类设置的 org.springframework.transaction.annotation.AnnotationTransactionAttributeSource, 用于获取TransactionAttribute 事务属性,也就是读取@Transactional 注解上的相关属性
pointcut 切入点: org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#TransactionAttributeSourcePointcut (是否需要进行事务的控制是在这个类进行判断的)
advice 通知: org.springframework.transaction.interceptor.TransactionInterceptor 事务拦截器。 (对事务的处理是在这个类)
3. 事务属性TransactionAttribute解析构造过程
0. 事务测试类:
package com.xm.ggn.test; import com.xm.ggn.bean.common.Message; import com.xm.ggn.mapper.common.MessageMapper; import org.springframework.aop.framework.AopContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Service; import javax.transaction.Transactional; import java.sql.SQLException; @Service // Primary可以理解为默认优先选择,不可以同时设置多个,内部实质是设置BeanDefinition的primary属性。 @Primary //@Transactional public class MessageService2Impl implements MessageService2 { @Autowired private MessageMapper messageMapper; @Override @Transactional public void tx1() { // 调用tx3方法会回滚,因为这里有事务直接,会走代理,且tx3方法会加入本事务 tx3(); } @Override public void tx2() { // 调用tx3方法不会回滚,因为这里没有事务。即使tx3有事务也不会走代理,因为通过内部方法调用不会走代理。解决办法查看tx4 方法 tx3(); } @Override @Transactional public void tx3() { Message message = new Message(); message.setTitle("tx3"); messageMapper.insert(message); int i = 1 / 0; } // 这样进行方法内部调用AOP会生效,主启动类加@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) 注解 @Override public void tx4() { MessageService2 messageService = (MessageService2) AopContext.currentProxy(); // 这样调用tx3会进行回滚,走的是代理类的方法 messageService.tx3(); } @Override @Transactional(rollbackOn = Exception.class) public void tx5() throws SQLException { Message message = new Message(); message.setTitle("tx3"); messageMapper.insert(message); throw new SQLException("xxx"); } }
1. AOP程序入口 org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept
@Nullable public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Object target = null; TargetSource targetSource = this.advised.getTargetSource(); Object var16; try { if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } target = targetSource.getTarget(); Class<?> targetClass = target != null ? target.getClass() : null; List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); } else { retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed(); } retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal); var16 = retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } return var16; }
这里的核心是 获取一个AOP调用链条, List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 所以是否需要事务控制只需要判断该chain 是否包含对应的Inteceptor。
(1) 针对tx1() 方法进行测试:获取到的chain 如下 = 可以看到有事务拦截器。则会用AOP进行事务处理
(2) 针对tx2() 方法进行测试: 获取到的chain 如下 = 可以看到没有事务相关的拦截器,则事务不会生效
2. 获取方法对应的AOP链分析
org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice 方法根据方法获取对应的AOP处理器链
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) { AdvisedSupport.MethodCacheKey cacheKey = new AdvisedSupport.MethodCacheKey(method); List<Object> cached = (List)this.methodCache.get(cacheKey); if (cached == null) { cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; }
可以看到会从缓存中拿, 如果缓存中拿不到就会调用方法org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice 获取并且放到缓存map。 所以需要从org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice 方法获取需要加载的AOP处理器链。
1. 分析 tx1() 方法获取AOP处理器链的过程:
最终获取的方法会打到: org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) { AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); Advisor[] advisors = config.getAdvisors(); List<Object> interceptorList = new ArrayList(advisors.length); Class<?> actualClass = targetClass != null ? targetClass : method.getDeclaringClass(); Boolean hasIntroductions = null; Advisor[] var9 = advisors; int var10 = advisors.length; for(int var11 = 0; var11 < var10; ++var11) { Advisor advisor = var9[var11]; if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pointcutAdvisor = (PointcutAdvisor)advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); boolean match; if (mm instanceof IntroductionAwareMethodMatcher) { if (hasIntroductions == null) { hasIntroductions = hasMatchingIntroductions(advisors, actualClass); } match = ((IntroductionAwareMethodMatcher)mm).matches(method, actualClass, hasIntroductions); } else { match = mm.matches(method, actualClass); } if (match) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); if (mm.isRuntime()) { MethodInterceptor[] var17 = interceptors; int var18 = interceptors.length; for(int var19 = 0; var19 < var18; ++var19) { MethodInterceptor interceptor = var17[var19]; interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } } else if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor)advisor; if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }
(1) config.getAdvisors(); 获取到所有的通知, 获取到的通知的数组如下:
(2) 遍历上面获取的通知,然后根据方法转交给MethodMatcher判断是否需要进行AOP处理器链调用。比如对于下标为2的Advisor获取到的MethodMatcher 是:
(3) 调用org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#matches 方法判断是否需要添加此AOP
@Override public boolean matches(Method method, Class<?> targetClass) { TransactionAttributeSource tas = getTransactionAttributeSource(); return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); }
-1》 这里首先获取TransactionAttributeSource, 这里获取到的就是AnnotationTransactionAttributeSource
-2》调用方法org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute 获取方法对应的事务属性
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { if (method.getDeclaringClass() == Object.class) { return null; } // First, see if we have a cached value. Object cacheKey = getCacheKey(method, targetClass); TransactionAttribute cached = this.attributeCache.get(cacheKey); if (cached != null) { // Value will either be canonical value indicating there is no transaction attribute, // or an actual transaction attribute. if (cached == NULL_TRANSACTION_ATTRIBUTE) { return null; } else { return cached; } } else { // We need to work it out. TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass); // Put it in the cache. if (txAttr == null) { this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE); } else { String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass); if (txAttr instanceof DefaultTransactionAttribute) { ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification); } if (logger.isTraceEnabled()) { logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr); } this.attributeCache.put(cacheKey, txAttr); } return txAttr; } }
- 这里先构造一个cacheKey, org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getCacheKey
protected Object getCacheKey(Method method, @Nullable Class<?> targetClass) { return new MethodClassKey(method, targetClass); }
对于上面的方法tx1() 获取到的cacheKey 如下:
- 用上面获取的cacheKey 作为key 从缓存map attributeCache 中拿取,org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#attributeCache如下:
private final Map<Object, TransactionAttribute> attributeCache = new ConcurrentHashMap<>(1024);
对于上面tx1() 方法获取到的TransactionAttribute 属性如下:可以看到默认的传播行为是PROPAGATION_REQUIRED, 默认的事务隔离级别是采用数据库的隔离级别
然后将获取到的TransactionAttribute 属性返回去。 也就是获取到此对象就需要事务AOP,否则不需要。
2. org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#attributeCache 存数据过程
这个缓存存数据的过程也就是解析方法对应的事务属性TransactionAttribute 的过程。
看是什么时候存储的,只需要查看什么时候put的,发现是在方法:org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute,断点查看调用链如下:
通过上面了解到,判断一个方法是否需要事务AOP处理是从org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#attributeCache 判断的,接下来研究这个map 是什么时候存入数据的。
(1) SpringIoC 对象创建过程中会调用org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary,
方法内部调用org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean 获取Advisor[],
最终会调用到方法 org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#matches, 也就是 上面判断是否需要 进行事务AOP, 然后调用到方法org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { if (method.getDeclaringClass() == Object.class) { return null; } // First, see if we have a cached value. Object cacheKey = getCacheKey(method, targetClass); TransactionAttribute cached = this.attributeCache.get(cacheKey); if (cached != null) { // Value will either be canonical value indicating there is no transaction attribute, // or an actual transaction attribute. if (cached == NULL_TRANSACTION_ATTRIBUTE) { return null; } else { return cached; } } else { // We need to work it out. TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass); // Put it in the cache. if (txAttr == null) { this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE); } else { String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass); if (txAttr instanceof DefaultTransactionAttribute) { ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification); } if (logger.isTraceEnabled()) { logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr); } this.attributeCache.put(cacheKey, txAttr); } return txAttr; } }
根据方法和类构造一个 cacheKey 对象(实际类型是org.springframework.core.MethodClassKey, 也就是将方法和class 封装成一个对象作为key),然后刚进来获取到的cached 为null,所以会走下面的第一次计算并且获取TransactionAttribute 对象。
(2) 接下来走 org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute:
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) { // Don't allow no-public methods as required. if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } // The method may be on an interface, but we need attributes from the target class. // If the target class is null, the method will be unchanged. Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass); // First try is the method in the target class. TransactionAttribute txAttr = findTransactionAttribute(specificMethod); if (txAttr != null) { return txAttr; } // Second try is the transaction attribute on the target class. txAttr = findTransactionAttribute(specificMethod.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } if (specificMethod != method) { // Fallback is to look at the original method. txAttr = findTransactionAttribute(method); if (txAttr != null) { return txAttr; } // Last fallback is the class of the original method. txAttr = findTransactionAttribute(method.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } } return null; }
这里的逻辑是:先从方法上获取,然后从类上获取。也就是先以方法的为准,然后以类上的为准。
1》首先从方法上获取注解:org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)
protected TransactionAttribute findTransactionAttribute(Method method) { return determineTransactionAttribute(method); }
转交给方法:org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#determineTransactionAttribute
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) { for (TransactionAnnotationParser parser : this.annotationParsers) { TransactionAttribute attr = parser.parseTransactionAnnotation(element); if (attr != null) { return attr; } } return null; }
这里获取Set<TransactionAnnotationParser> annotationParsers , 然后遍历获取TransactionAttribute, annotationParsers 如下:
可以看到这里有两个解析器。第一个是解析Spring 包下面的Transactional注解的解析器, 第二个是解析javax包下面的Transactional 注解的解析器。也就是两个注解都可以,对应两个不同的解析器。
- org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement) 解析个过程如下:
首先获取Spring包下面的注解:
@Override @Nullable public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) { AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes( element, Transactional.class, false, false); if (attributes != null) { return parseTransactionAnnotation(attributes); } else { return null; } }
获取到之后调用方法parseTransactionAnnotation 解析并且封装事务属性, 获取注解的方法委托给Spring 的工具类 org.springframework.core.annotation.AnnotatedElementUtils#findMergedAnnotationAttributes(java.lang.reflect.AnnotatedElement, java.lang.Class<? extends java.lang.annotation.Annotation>, boolean, boolean), 封装TransactionAttribute 对象的过程如下:
public TransactionAttribute parseTransactionAnnotation(Transactional ann) { return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false)); } protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) { RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); Propagation propagation = attributes.getEnum("propagation"); rbta.setPropagationBehavior(propagation.value()); Isolation isolation = attributes.getEnum("isolation"); rbta.setIsolationLevel(isolation.value()); rbta.setTimeout(attributes.getNumber("timeout").intValue()); rbta.setReadOnly(attributes.getBoolean("readOnly")); rbta.setQualifier(attributes.getString("value")); List<RollbackRuleAttribute> rollbackRules = new ArrayList<>(); for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) { rollbackRules.add(new RollbackRuleAttribute(rbRule)); } for (String rbRule : attributes.getStringArray("rollbackForClassName")) { rollbackRules.add(new RollbackRuleAttribute(rbRule)); } for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) { rollbackRules.add(new NoRollbackRuleAttribute(rbRule)); } for (String rbRule : attributes.getStringArray("noRollbackForClassName")) { rollbackRules.add(new NoRollbackRuleAttribute(rbRule)); } rbta.setRollbackRules(rollbackRules); return rbta; }
org.springframework.transaction.annotation.JtaTransactionAnnotationParser事务解析器中获取到javax.transaction.Transactional 注解封装事务属性过程如下:
org.springframework.transaction.annotation.JtaTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement) 方法如下:
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) { AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes( element, javax.transaction.Transactional.class); if (attributes != null) { return parseTransactionAnnotation(attributes); } else { return null; } }
首先获取方法Transactional 注解的属性并封装到AnnotationAttributes, 然后调用:调用方法org.springframework.transaction.annotation.JtaTransactionAnnotationParser#parseTransactionAnnotation(org.springframework.core.annotation.AnnotationAttributes) 组装成 TransactionAttribute
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) { RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); // 获取事务的 传播特性 rbta.setPropagationBehaviorName( RuleBasedTransactionAttribute.PREFIX_PROPAGATION + attributes.getEnum("value").toString()); // 建立rolebackOn 和 dontRollbackOn 特性 List<RollbackRuleAttribute> rollbackRules = new ArrayList<>(); for (Class<?> rbRule : attributes.getClassArray("rollbackOn")) { rollbackRules.add(new RollbackRuleAttribute(rbRule)); } for (Class<?> rbRule : attributes.getClassArray("dontRollbackOn")) { rollbackRules.add(new NoRollbackRuleAttribute(rbRule)); } rbta.setRollbackRules(rollbackRules); return rbta; }
将获取到的TransactionAttribute 返回给方法org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute。 然后缓存到本地的attributeCache 属性中。
4. 事务处理过程分析
上面研究了事务属性的解析过程,大致过程是先解析方法上是否有事务属性,也就是是否有@Transactional 注解(包含javax.transaction包和Spring包的,对应两种解析器); 如果方法没找到就从类上找,类上找的时候也会从类继承的接口上找,所以事务注解具有了继承性。找到之后存到org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#attributeCache缓存Map中;如果没找到也存一个默认的空对象进去,Map的key是类和方法组成的一个对象。 此缓存Map 用于之后判断某个方法在AOP调用链获取过程中判断是否需要进行事务通知的处理。接下来研究事务通知的处理过程。
1. 事务通知入口:
org.springframework.transaction.interceptor.TransactionInterceptor#invoke (该方法继承自org.aopalliance.intercept.MethodInterceptor#invoke)
@Override @Nullable 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); }
2. 然后请求转交给父类org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
@Nullable protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. TransactionAttributeSource tas = getTransactionAttributeSource(); final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); final TransactionManager tm = determineTransactionManager(txAttr); if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) { ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> { if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) { throw new TransactionUsageException( "Unsupported annotated transaction on suspending function detected: " + method + ". Use TransactionalOperator.transactional extensions instead."); } ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType()); if (adapter == null) { throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " + method.getReturnType()); } return new ReactiveTransactionSupport(adapter); }); return txSupport.invokeWithinTransaction( method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm); } PlatformTransactionManager ptm = asPlatformTransactionManager(tm); final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification); Object retVal; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } if (vavrPresent && VavrDelegate.isVavrTry(retVal)) { // Set rollback-only in case of Vavr failure matching our rollback rules... TransactionStatus status = txInfo.getTransactionStatus(); if (status != null && txAttr != null) { retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status); } } commitTransactionAfterReturning(txInfo); return retVal; } else { final ThrowableHolder throwableHolder = new ThrowableHolder(); // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in. try { Object result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> { TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status); try { Object retVal = invocation.proceedWithInvocation(); if (vavrPresent && VavrDelegate.isVavrTry(retVal)) { // Set rollback-only in case of Vavr failure matching our rollback rules... retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status); } return retVal; } catch (Throwable ex) { if (txAttr.rollbackOn(ex)) { // A RuntimeException: will lead to a rollback. if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } else { throw new ThrowableHolderException(ex); } } else { // A normal return value: will lead to a commit. throwableHolder.throwable = ex; return null; } } finally { cleanupTransactionInfo(txInfo); } }); // Check result state: It might indicate a Throwable to rethrow. if (throwableHolder.throwable != null) { throw throwableHolder.throwable; } return result; } catch (ThrowableHolderException ex) { throw ex.getCause(); } catch (TransactionSystemException ex2) { if (throwableHolder.throwable != null) { logger.error("Application exception overridden by commit exception", throwableHolder.throwable); ex2.initApplicationException(throwableHolder.throwable); } throw ex2; } catch (Throwable ex2) { if (throwableHolder.throwable != null) { logger.error("Application exception overridden by commit exception", throwableHolder.throwable); } throw ex2; } } }
所以事务的核心逻辑代码是在这个方法内部,下面着重分析这个方法的代码逻辑。 也可以看到这里使用的是一个环绕通知。
测试:
$ curl http://localhost:8088/tx1 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 78 0 78 0 0 6 0 --:--:-- 0:00:12 --:--:-- 21{"success":false,"data":null,"msg":"系统内部错误","errorCode":"u200000"}
主要做的事情如下:
(1) 获取TransactionAttribute 对象, 获取到的对象如下:
tas.getTransactionAttribute(method, targetClass) 获取事务属性, 实际最终也是调用方法 org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute 从org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#attributeCache 获取
(2) createTransactionIfNecessary方法准备事务相关东西
org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary 方法源码如下:
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, final String joinpointIdentification) { // If no name specified, apply method identification as transaction name. if (txAttr != null && txAttr.getName() == null) { txAttr = new DelegatingTransactionAttribute(txAttr) { @Override public String getName() { return joinpointIdentification; } }; } TransactionStatus status = null; if (txAttr != null) { if (tm != null) { status = tm.getTransaction(txAttr); } else { if (logger.isDebugEnabled()) { logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured"); } } } return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); }
tm.getTransaction(txAttr); 方法 调用org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction 获取事务
@Override public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException { // Use defaults if no transaction definition given. TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults()); Object transaction = doGetTransaction(); boolean debugEnabled = logger.isDebugEnabled(); if (isExistingTransaction(transaction)) { // Existing transaction found -> check propagation behavior to find out how to behave. return handleExistingTransaction(def, transaction, debugEnabled); } // Check definition settings for new transaction. if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) { throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout()); } // No existing transaction found -> check propagation behavior to find out how to proceed. if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) { throw new IllegalTransactionStateException( "No existing transaction found for transaction marked with propagation 'mandatory'"); } else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { SuspendedResourcesHolder suspendedResources = suspend(null); if (debugEnabled) { logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def); } try { return startTransaction(def, transaction, debugEnabled, suspendedResources); } catch (RuntimeException | Error ex) { resume(null, suspendedResources); throw ex; } } else { // Create "empty" transaction: no actual transaction, but potentially synchronization. if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) { logger.warn("Custom isolation level specified but no actual transaction initiated; " + "isolation level will effectively be ignored: " + def); } boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null); } }
这里会判断是否有事务,没有事务的情况下判断事务的传播行为,然后会调用org.springframework.transaction.support.AbstractPlatformTransactionManager#startTransaction开启事务;如果有事务环境isExistingTransaction(transaction) 返回true, 会调用org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction 根据不同的事务传播行为做特殊的处理 (下节研究不同传播行为的处理)
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) { boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); doBegin(transaction, definition); prepareSynchronization(status, definition); return status; }
首先创建DefaultTransactionStatus 会记录事务的一些属性到该对象;然后调用 org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin 开启事务
protected void doBegin(Object transaction, TransactionDefinition definition) { DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)transaction; Connection con = null; try { if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) { Connection newCon = this.obtainDataSource().getConnection(); if (this.logger.isDebugEnabled()) { this.logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction"); } txObject.setConnectionHolder(new ConnectionHolder(newCon), true); } txObject.getConnectionHolder().setSynchronizedWithTransaction(true); con = txObject.getConnectionHolder().getConnection(); Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition); txObject.setPreviousIsolationLevel(previousIsolationLevel); txObject.setReadOnly(definition.isReadOnly()); if (con.getAutoCommit()) { txObject.setMustRestoreAutoCommit(true); if (this.logger.isDebugEnabled()) { this.logger.debug("Switching JDBC Connection [" + con + "] to manual commit"); } con.setAutoCommit(false); } this.prepareTransactionalConnection(con, definition); txObject.getConnectionHolder().setTransactionActive(true); int timeout = this.determineTimeout(definition); if (timeout != -1) { txObject.getConnectionHolder().setTimeoutInSeconds(timeout); } if (txObject.isNewConnectionHolder()) { TransactionSynchronizationManager.bindResource(this.obtainDataSource(), txObject.getConnectionHolder()); } } catch (Throwable var7) { if (txObject.isNewConnectionHolder()) { DataSourceUtils.releaseConnection(con, this.obtainDataSource()); txObject.setConnectionHolder((ConnectionHolder)null, false); } throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", var7); } }
做完上面操作然后调用org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfo 将相关信息封装到一个TransactionInfo 对象中:创建对象,然后txInfo.bindToThread与当前线程进行绑定(ThreadLocal)
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, String joinpointIdentification, @Nullable TransactionStatus status) { TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification); if (txAttr != null) { // We need a transaction for this method... if (logger.isTraceEnabled()) { logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]"); } // The transaction manager will flag an error if an incompatible tx already exists. txInfo.newTransactionStatus(status); } else { // The TransactionInfo.hasTransaction() method will return false. We created it only // to preserve the integrity of the ThreadLocal stack maintained in this class. if (logger.isTraceEnabled()) { logger.trace("No need to create transaction for [" + joinpointIdentification + "]: This method is not transactional."); } } // We always bind the TransactionInfo to the thread, even if we didn't create // a new transaction here. This guarantees that the TransactionInfo stack // will be managed correctly even if no transaction was created by this aspect. txInfo.bindToThread(); return txInfo; }
(3) 调用业务方法
invocation.proceedWithInvocation();
(4) 如果捕捉到异常之后调用方法completeTransactionAfterThrowing 进行事务异常处理; 然后将异常再向外抛(finally代码块清掉事务相关状态)
org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing 如下:
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) { if (txInfo != null && txInfo.getTransactionStatus() != null) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex); } if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) { try { txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by rollback exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException | Error ex2) { logger.error("Application exception overridden by rollback exception", ex); throw ex2; } } else { // We don't roll back on this exception. // Will still roll back if TransactionStatus.isRollbackOnly() is true. try { txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by commit exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException | Error ex2) { logger.error("Application exception overridden by commit exception", ex); throw ex2; } } } }
如果是支持回滚的异常类型会进行回滚, org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn方法如下:(也就是默认是Error 和 RuntimeException 类型的异常会进行回滚)
public boolean rollbackOn(Throwable ex) { return (ex instanceof RuntimeException || ex instanceof Error); }
调用org.springframework.transaction.support.AbstractPlatformTransactionManager#rollback 进行回滚:
public final void rollback(TransactionStatus status) throws TransactionException { if (status.isCompleted()) { throw new IllegalTransactionStateException( "Transaction is already completed - do not call commit or rollback more than once per transaction"); } DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status; processRollback(defStatus, false); }
org.springframework.transaction.support.AbstractPlatformTransactionManager#processRollback:
private void processRollback(DefaultTransactionStatus status, boolean unexpected) { try { boolean unexpectedRollback = unexpected; try { triggerBeforeCompletion(status); if (status.hasSavepoint()) { if (status.isDebug()) { logger.debug("Rolling back transaction to savepoint"); } status.rollbackToHeldSavepoint(); } else if (status.isNewTransaction()) { if (status.isDebug()) { logger.debug("Initiating transaction rollback"); } doRollback(status); } else { // Participating in larger transaction if (status.hasTransaction()) { if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) { if (status.isDebug()) { logger.debug("Participating transaction failed - marking existing transaction as rollback-only"); } doSetRollbackOnly(status); } else { if (status.isDebug()) { logger.debug("Participating transaction failed - letting transaction originator decide on rollback"); } } } else { logger.debug("Should roll back transaction but cannot - no transaction available"); } // Unexpected rollback only matters here if we're asked to fail early if (!isFailEarlyOnGlobalRollbackOnly()) { unexpectedRollback = false; } } } catch (RuntimeException | Error ex) { triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN); throw ex; } triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK); // Raise UnexpectedRollbackException if we had a global rollback-only marker if (unexpectedRollback) { throw new UnexpectedRollbackException( "Transaction rolled back because it has been marked as rollback-only"); } } finally { cleanupAfterCompletion(status); } }
最终调用到: org.springframework.jdbc.datasource.DataSourceTransactionManager#doRollback 进行回滚:
protected void doRollback(DefaultTransactionStatus status) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction(); Connection con = txObject.getConnectionHolder().getConnection(); if (status.isDebug()) { logger.debug("Rolling back JDBC transaction on Connection [" + con + "]"); } try { con.rollback(); } catch (SQLException ex) { throw new TransactionSystemException("Could not roll back JDBC transaction", ex); } }
(5) 如果没有捕捉到异常,finally代码块清掉事务相关状态; 然后对事务进行commit。
org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning:
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) { if (txInfo != null && txInfo.getTransactionStatus() != null) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]"); } txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } }
org.springframework.transaction.support.AbstractPlatformTransactionManager#commit:
public final void commit(TransactionStatus status) throws TransactionException { if (status.isCompleted()) { throw new IllegalTransactionStateException( "Transaction is already completed - do not call commit or rollback more than once per transaction"); } DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status; if (defStatus.isLocalRollbackOnly()) { if (defStatus.isDebug()) { logger.debug("Transactional code has requested rollback"); } processRollback(defStatus, false); return; } if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) { if (defStatus.isDebug()) { logger.debug("Global transaction is marked as rollback-only but transactional code requested commit"); } processRollback(defStatus, true); return; } processCommit(defStatus); }
org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit: (提交的核心逻辑)
private void processCommit(DefaultTransactionStatus status) throws TransactionException { try { boolean beforeCompletionInvoked = false; try { boolean unexpectedRollback = false; prepareForCommit(status); triggerBeforeCommit(status); triggerBeforeCompletion(status); beforeCompletionInvoked = true; if (status.hasSavepoint()) { if (status.isDebug()) { logger.debug("Releasing transaction savepoint"); } unexpectedRollback = status.isGlobalRollbackOnly(); status.releaseHeldSavepoint(); } else if (status.isNewTransaction()) { if (status.isDebug()) { logger.debug("Initiating transaction commit"); } unexpectedRollback = status.isGlobalRollbackOnly(); doCommit(status); } else if (isFailEarlyOnGlobalRollbackOnly()) { unexpectedRollback = status.isGlobalRollbackOnly(); } // Throw UnexpectedRollbackException if we have a global rollback-only // marker but still didn't get a corresponding exception from commit. if (unexpectedRollback) { throw new UnexpectedRollbackException( "Transaction silently rolled back because it has been marked as rollback-only"); } } catch (UnexpectedRollbackException ex) { // can only be caused by doCommit triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK); throw ex; } catch (TransactionException ex) { // can only be caused by doCommit if (isRollbackOnCommitFailure()) { doRollbackOnCommitException(status, ex); } else { triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN); } throw ex; } catch (RuntimeException | Error ex) { if (!beforeCompletionInvoked) { triggerBeforeCompletion(status); } doRollbackOnCommitException(status, ex); throw ex; } // Trigger afterCommit callbacks, with an exception thrown there // propagated to callers but the transaction still considered as committed. try { triggerAfterCommit(status); } finally { triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED); } } finally { cleanupAfterCompletion(status); } }
1》如果是newTransaction(如果是嵌套事务newTransaction 返回值为false), 调用doCommit(status);保存事务信息。org.springframework.jdbc.datasource.DataSourceTransactionManager#doCommit:
protected void doCommit(DefaultTransactionStatus status) { DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)status.getTransaction(); Connection con = txObject.getConnectionHolder().getConnection(); if (status.isDebug()) { this.logger.debug("Committing JDBC transaction on Connection [" + con + "]"); } try { con.commit(); } catch (SQLException var5) { throw new TransactionSystemException("Could not commit JDBC transaction", var5); } }
2》有个cleanupAfterCompletion(status) 方法,进行事务提交的后续操作,会调用到: org.springframework.transaction.support.AbstractPlatformTransactionManager#cleanupAfterCompletion
/** * Clean up after completion, clearing synchronization if necessary, * and invoking doCleanupAfterCompletion. * @param status object representing the transaction * @see #doCleanupAfterCompletion */ private void cleanupAfterCompletion(DefaultTransactionStatus status) { status.setCompleted(); if (status.isNewSynchronization()) { TransactionSynchronizationManager.clear(); } if (status.isNewTransaction()) { doCleanupAfterCompletion(status.getTransaction()); } if (status.getSuspendedResources() != null) { if (status.isDebug()) { logger.debug("Resuming suspended transaction after completion of inner transaction"); } Object transaction = (status.hasTransaction() ? status.getTransaction() : null); resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources()); } }
这里有几个重要步骤:
第一:如果是newTransaction, 调用org.springframework.transaction.support.TransactionSynchronizationManager#clear 清理ThreadLocal 信息
public static void clear() { synchronizations.remove(); currentTransactionName.remove(); currentTransactionReadOnly.remove(); currentTransactionIsolationLevel.remove(); actualTransactionActive.remove(); }
第二: 如果是newReansaction, 调用org.springframework.jdbc.datasource.DataSourceTransactionManager#doCleanupAfterCompletion 恢复Connection
@Override protected void doCleanupAfterCompletion(Object transaction) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; // Remove the connection holder from the thread, if exposed. if (txObject.isNewConnectionHolder()) { TransactionSynchronizationManager.unbindResource(obtainDataSource()); } // Reset connection. Connection con = txObject.getConnectionHolder().getConnection(); try { if (txObject.isMustRestoreAutoCommit()) { con.setAutoCommit(true); } DataSourceUtils.resetConnectionAfterTransaction( con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly()); } catch (Throwable ex) { logger.debug("Could not reset JDBC Connection after transaction", ex); } if (txObject.isNewConnectionHolder()) { if (logger.isDebugEnabled()) { logger.debug("Releasing JDBC Connection [" + con + "] after transaction"); } DataSourceUtils.releaseConnection(con, this.dataSource); } txObject.getConnectionHolder().clear(); }
第三: 如果有挂起的事务(比如在PROPAGATION_REQUIRED_NEW 传播行为下,第二个事务会挂起第一个已经存在的事务), 调用org.springframework.transaction.support.AbstractPlatformTransactionManager#resume 恢复事务
protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder) throws TransactionException { if (resourcesHolder != null) { Object suspendedResources = resourcesHolder.suspendedResources; if (suspendedResources != null) { doResume(transaction, suspendedResources); } List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations; if (suspendedSynchronizations != null) { TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive); TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel); TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly); TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name); doResumeSynchronization(suspendedSynchronizations); } } }
总结:事务过程中几个重要的类
(1) org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration 事务自动配置的相关类
(2) org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor 可以理解为切面Aspect的角色(内部维护Point与Advisor)
(3) org.springframework.transaction.interceptor.TransactionAttributeSource 用于获取TransactionAttribute 事务属性,也就是读取@Transactional 注解上的相关属性
(4) org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#TransactionAttributeSourcePointcut (是否需要进行事务的控制是在这个类进行判断的)
(5) org.springframework.transaction.interceptor.TransactionInterceptor 事务拦截器。 (对事务的处理是在这个类)
(6) org.springframework.transaction.interceptor.TransactionAttribute 封装事物属性的接口, 也就是封装@Transactional 注解上面的属性
(7) org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo 封装事务信息的类,里面包括的重要属性如下:
@Nullable private final PlatformTransactionManager transactionManager; @Nullable private final TransactionAttribute transactionAttribute; private final String joinpointIdentification; @Nullable private TransactionStatus transactionStatus; @Nullable private TransactionInfo oldTransactionInfo;
(8) org.springframework.transaction.TransactionManager 事务管理器。 操作事务的方法都在这个类里面。用的最多的是org.springframework.transaction.PlatformTransactionManager 接口的实现类
补充: 测试org.springframework.core.annotation.AnnotatedElementUtils#findMergedAnnotationAttributes 方法可以获取接口上的注解
1. 注解类
package com.xm.ggn.test.annotation; import java.lang.annotation.*; @Inherited @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnno1 { String value() default "111222"; }
2. 接口
package com.xm.ggn.test.annotation; @MyAnno1("123456") public interface Interface1 { void fun1(); }
3. 类1
package com.xm.ggn.test.annotation; public class Class1 implements Interface1{ @Override public void fun1() { System.out.println("fun1 called!!!"); } }
4. Client
package com.xm.ggn.test.annotation; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotationAttributes; public class Client { public static void main(String[] args) { AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes( Class1.class, MyAnno1.class, false, false); System.out.println(attributes); } }
5. 测试结果:
补充:javax包下和Spring包下面注解@Transactional的区别
两者都可以实现事务的功能,是使用了两个不同的parser来进行解析。
(1) javax包下的@Transactional 注解如下: javax 提供的注解,没有提供指定隔离级别、是否只读等参数,隔离级别也是数据库默认的隔离级别、只读默认是false。参考:org.springframework.transaction.annotation.JtaTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement) 创建的时候默认继承自org.springframework.transaction.support.DefaultTransactionDefinition#isolationLevel
package javax.transaction; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.enterprise.util.Nonbinding; import javax.interceptor.InterceptorBinding; @Inherited @InterceptorBinding @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Transactional { Transactional.TxType value() default Transactional.TxType.REQUIRED; @Nonbinding Class[] rollbackOn() default {}; @Nonbinding Class[] dontRollbackOn() default {}; public static enum TxType { REQUIRED, REQUIRES_NEW, MANDATORY, SUPPORTS, NOT_SUPPORTED, NEVER; private TxType() { } } }
(2) Spring 包下的Transactional 注解如下:解析方法为 org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)
package org.springframework.transaction.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; import org.springframework.transaction.TransactionDefinition; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Transactional { @AliasFor("transactionManager") String value() default ""; @AliasFor("value") String transactionManager() default ""; Propagation propagation() default Propagation.REQUIRED; Isolation isolation() default Isolation.DEFAULT; int timeout() default TransactionDefinition.TIMEOUT_DEFAULT; boolean readOnly() default false; Class<? extends Throwable>[] rollbackFor() default {}; String[] rollbackForClassName() default {}; Class<? extends Throwable>[] noRollbackFor() default {}; String[] noRollbackForClassName() default {}; }
补充:TransactionAttribute继承自接口 TransactionDefinition, TransactionDefinition 接口定义了事务传播行为和隔离级别的一些变量:
package org.springframework.transaction; import org.springframework.lang.Nullable; /** * Interface that defines Spring-compliant transaction properties. * Based on the propagation behavior definitions analogous to EJB CMT attributes. * * <p>Note that isolation level and timeout settings will not get applied unless * an actual new transaction gets started. As only {@link #PROPAGATION_REQUIRED}, * {@link #PROPAGATION_REQUIRES_NEW} and {@link #PROPAGATION_NESTED} can cause * that, it usually doesn't make sense to specify those settings in other cases. * Furthermore, be aware that not all transaction managers will support those * advanced features and thus might throw corresponding exceptions when given * non-default values. * * <p>The {@link #isReadOnly() read-only flag} applies to any transaction context, * whether backed by an actual resource transaction or operating non-transactionally * at the resource level. In the latter case, the flag will only apply to managed * resources within the application, such as a Hibernate {@code Session}. * * @author Juergen Hoeller * @since 08.05.2003 * @see PlatformTransactionManager#getTransaction(TransactionDefinition) * @see org.springframework.transaction.support.DefaultTransactionDefinition * @see org.springframework.transaction.interceptor.TransactionAttribute */ public interface TransactionDefinition { /** * Support a current transaction; create a new one if none exists. * Analogous to the EJB transaction attribute of the same name. * <p>This is typically the default setting of a transaction definition, * and typically defines a transaction synchronization scope. */ int PROPAGATION_REQUIRED = 0; /** * Support a current transaction; execute non-transactionally if none exists. * Analogous to the EJB transaction attribute of the same name. * <p><b>NOTE:</b> For transaction managers with transaction synchronization, * {@code PROPAGATION_SUPPORTS} is slightly different from no transaction * at all, as it defines a transaction scope that synchronization might apply to. * As a consequence, the same resources (a JDBC {@code Connection}, a * Hibernate {@code Session}, etc) will be shared for the entire specified * scope. Note that the exact behavior depends on the actual synchronization * configuration of the transaction manager! * <p>In general, use {@code PROPAGATION_SUPPORTS} with care! In particular, do * not rely on {@code PROPAGATION_REQUIRED} or {@code PROPAGATION_REQUIRES_NEW} * <i>within</i> a {@code PROPAGATION_SUPPORTS} scope (which may lead to * synchronization conflicts at runtime). If such nesting is unavoidable, make sure * to configure your transaction manager appropriately (typically switching to * "synchronization on actual transaction"). * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION */ int PROPAGATION_SUPPORTS = 1; /** * Support a current transaction; throw an exception if no current transaction * exists. Analogous to the EJB transaction attribute of the same name. * <p>Note that transaction synchronization within a {@code PROPAGATION_MANDATORY} * scope will always be driven by the surrounding transaction. */ int PROPAGATION_MANDATORY = 2; /** * Create a new transaction, suspending the current transaction if one exists. * Analogous to the EJB transaction attribute of the same name. * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box * on all transaction managers. This in particular applies to * {@link org.springframework.transaction.jta.JtaTransactionManager}, * which requires the {@code javax.transaction.TransactionManager} to be * made available it to it (which is server-specific in standard Java EE). * <p>A {@code PROPAGATION_REQUIRES_NEW} scope always defines its own * transaction synchronizations. Existing synchronizations will be suspended * and resumed appropriately. * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager */ int PROPAGATION_REQUIRES_NEW = 3; /** * Do not support a current transaction; rather always execute non-transactionally. * Analogous to the EJB transaction attribute of the same name. * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box * on all transaction managers. This in particular applies to * {@link org.springframework.transaction.jta.JtaTransactionManager}, * which requires the {@code javax.transaction.TransactionManager} to be * made available it to it (which is server-specific in standard Java EE). * <p>Note that transaction synchronization is <i>not</i> available within a * {@code PROPAGATION_NOT_SUPPORTED} scope. Existing synchronizations * will be suspended and resumed appropriately. * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager */ int PROPAGATION_NOT_SUPPORTED = 4; /** * Do not support a current transaction; throw an exception if a current transaction * exists. Analogous to the EJB transaction attribute of the same name. * <p>Note that transaction synchronization is <i>not</i> available within a * {@code PROPAGATION_NEVER} scope. */ int PROPAGATION_NEVER = 5; /** * Execute within a nested transaction if a current transaction exists, * behave like {@link #PROPAGATION_REQUIRED} otherwise. There is no * analogous feature in EJB. * <p><b>NOTE:</b> Actual creation of a nested transaction will only work on * specific transaction managers. Out of the box, this only applies to the JDBC * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager} * when working on a JDBC 3.0 driver. Some JTA providers might support * nested transactions as well. * @see org.springframework.jdbc.datasource.DataSourceTransactionManager */ int PROPAGATION_NESTED = 6; /** * Use the default isolation level of the underlying datastore. * All other levels correspond to the JDBC isolation levels. * @see java.sql.Connection */ int ISOLATION_DEFAULT = -1; /** * Indicates that dirty reads, non-repeatable reads and phantom reads * can occur. * <p>This level allows a row changed by one transaction to be read by another * transaction before any changes in that row have been committed (a "dirty read"). * If any of the changes are rolled back, the second transaction will have * retrieved an invalid row. * @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED */ int ISOLATION_READ_UNCOMMITTED = 1; // same as java.sql.Connection.TRANSACTION_READ_UNCOMMITTED; /** * Indicates that dirty reads are prevented; non-repeatable reads and * phantom reads can occur. * <p>This level only prohibits a transaction from reading a row * with uncommitted changes in it. * @see java.sql.Connection#TRANSACTION_READ_COMMITTED */ int ISOLATION_READ_COMMITTED = 2; // same as java.sql.Connection.TRANSACTION_READ_COMMITTED; /** * Indicates that dirty reads and non-repeatable reads are prevented; * phantom reads can occur. * <p>This level prohibits a transaction from reading a row with uncommitted changes * in it, and it also prohibits the situation where one transaction reads a row, * a second transaction alters the row, and the first transaction re-reads the row, * getting different values the second time (a "non-repeatable read"). * @see java.sql.Connection#TRANSACTION_REPEATABLE_READ */ int ISOLATION_REPEATABLE_READ = 4; // same as java.sql.Connection.TRANSACTION_REPEATABLE_READ; /** * Indicates that dirty reads, non-repeatable reads and phantom reads * are prevented. * <p>This level includes the prohibitions in {@link #ISOLATION_REPEATABLE_READ} * and further prohibits the situation where one transaction reads all rows that * satisfy a {@code WHERE} condition, a second transaction inserts a row * that satisfies that {@code WHERE} condition, and the first transaction * re-reads for the same condition, retrieving the additional "phantom" row * in the second read. * @see java.sql.Connection#TRANSACTION_SERIALIZABLE */ int ISOLATION_SERIALIZABLE = 8; // same as java.sql.Connection.TRANSACTION_SERIALIZABLE; /** * Use the default timeout of the underlying transaction system, * or none if timeouts are not supported. */ int TIMEOUT_DEFAULT = -1; /** * Return the propagation behavior. * <p>Must return one of the {@code PROPAGATION_XXX} constants * defined on {@link TransactionDefinition this interface}. * <p>The default is {@link #PROPAGATION_REQUIRED}. * @return the propagation behavior * @see #PROPAGATION_REQUIRED * @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive() */ default int getPropagationBehavior() { return PROPAGATION_REQUIRED; } /** * Return the isolation level. * <p>Must return one of the {@code ISOLATION_XXX} constants defined on * {@link TransactionDefinition this interface}. Those constants are designed * to match the values of the same constants on {@link java.sql.Connection}. * <p>Exclusively designed for use with {@link #PROPAGATION_REQUIRED} or * {@link #PROPAGATION_REQUIRES_NEW} since it only applies to newly started * transactions. Consider switching the "validateExistingTransactions" flag to * "true" on your transaction manager if you'd like isolation level declarations * to get rejected when participating in an existing transaction with a different * isolation level. * <p>The default is {@link #ISOLATION_DEFAULT}. Note that a transaction manager * that does not support custom isolation levels will throw an exception when * given any other level than {@link #ISOLATION_DEFAULT}. * @return the isolation level * @see #ISOLATION_DEFAULT * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setValidateExistingTransaction */ default int getIsolationLevel() { return ISOLATION_DEFAULT; } /** * Return the transaction timeout. * <p>Must return a number of seconds, or {@link #TIMEOUT_DEFAULT}. * <p>Exclusively designed for use with {@link #PROPAGATION_REQUIRED} or * {@link #PROPAGATION_REQUIRES_NEW} since it only applies to newly started * transactions. * <p>Note that a transaction manager that does not support timeouts will throw * an exception when given any other timeout than {@link #TIMEOUT_DEFAULT}. * <p>The default is {@link #TIMEOUT_DEFAULT}. * @return the transaction timeout */ default int getTimeout() { return TIMEOUT_DEFAULT; } /** * Return whether to optimize as a read-only transaction. * <p>The read-only flag applies to any transaction context, whether backed * by an actual resource transaction ({@link #PROPAGATION_REQUIRED}/ * {@link #PROPAGATION_REQUIRES_NEW}) or operating non-transactionally at * the resource level ({@link #PROPAGATION_SUPPORTS}). In the latter case, * the flag will only apply to managed resources within the application, * such as a Hibernate {@code Session}. * <p>This just serves as a hint for the actual transaction subsystem; * it will <i>not necessarily</i> cause failure of write access attempts. * A transaction manager which cannot interpret the read-only hint will * <i>not</i> throw an exception when asked for a read-only transaction. * @return {@code true} if the transaction is to be optimized as read-only * ({@code false} by default) * @see org.springframework.transaction.support.TransactionSynchronization#beforeCommit(boolean) * @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly() */ default boolean isReadOnly() { return false; } /** * Return the name of this transaction. Can be {@code null}. * <p>This will be used as the transaction name to be shown in a * transaction monitor, if applicable (for example, WebLogic's). * <p>In case of Spring's declarative transactions, the exposed name will be * the {@code fully-qualified class name + "." + method name} (by default). * @return the name of this transaction ({@code null} by default} * @see org.springframework.transaction.interceptor.TransactionAspectSupport * @see org.springframework.transaction.support.TransactionSynchronizationManager#getCurrentTransactionName() */ @Nullable default String getName() { return null; } // Static builder methods /** * Return an unmodifiable {@code TransactionDefinition} with defaults. * <p>For customization purposes, use the modifiable * {@link org.springframework.transaction.support.DefaultTransactionDefinition} * instead. * @since 5.2 */ static TransactionDefinition withDefaults() { return StaticTransactionDefinition.INSTANCE; } }