Spring Transaction 从实例读源码
来源:互联网 发布:云视通网络监控tv版 编辑:程序博客网 时间:2024/05/20 08:44
Spring Transaction 从实例读源码
更为完整的笔记传送门 Github
实例
public interface LoginService { void login(RegisterDTO dto);}@Servicepublic class LoginServiceImpl implements LoginService{ @Override @Transactional(rollbackFor = RuntimeException.class,propagation = Propagation.NESTED) public void login(RegisterDTO dto) { System.out.println("login..."); throw new RuntimeException("exception in loginservice"); }}public interface UserService { void addUser(RegisterDTO dto);}@Servicepublic class UserServiceImpl implements UserService{ @Transactional(rollbackFor = RuntimeException.class,propagation = Propagation.NESTED) @Override public void addUser(RegisterDTO dto) { System.out.println("addUser..."); }}public interface RegisterService { void register(RegisterDTO dto);}@Servicepublic class RegisterServiceImpl implements RegisterService{ @Autowired private LoginService loginService; @Autowired private UserService userService; @Transactional(rollbackFor = RuntimeException.class,propagation = Propagation.NESTED) @Override public void register(RegisterDTO dto) { System.out.println("registering..."); loginService.login(dto); System.out.println("invoke other methods..."); userService.addUser(dto); }}@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath*:spring/spring-*.xml")@WebAppConfigurationpublic class TransactionTest { @Autowired private RegisterService registerService; @Test public void test(){ registerService.register(new RegisterDTO()); }}
约定
方法调用顺序约定
这里用 1.1) 、1.2) 来表示1)方法中的比较重要的步骤1和步骤2。
另外并不是从一开始就进行编号,而是到重要的方法时才开始编号。
public class Main { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) applicationContext.getBean("userService"); userService.login(); }}
比如Main类中的main方法记为1),则可以将new ClassPathXmlApplicationContext记为1.1),将getBean记为1.2)。
关注点约束
我们只关注源码中的核心的业务逻辑,由于Spring过于复杂,所以哪怕只掌握其核心逻辑就很不容易了。另外文章是从实例看源码的,所以可能源码中有多条执行路径,但我们只关注实例中经过的逻辑,其他的执行路径可能会被忽略。
Transaction概述
Spring Transaction是在Spring tx模块中实现的,Spring事务功能依赖于Spring的AOP模块,阅读tx模块源码前最好先阅读Spring AOP的源码。
Spring Transaction的功能可以分为两个部分,一个部分是解析事务标签,另一部分是创建事务代理。
解析事务标签与解析AOP标签非常类似,它解析<tx:annotation-driven />
标签,注册了一个InfrastructureAdvisorAutoProxyCreator类和三个bean。这三个bean支撑起了整个的事务功能。其中的两个bean(TransactionInterceptor和AnnotationTransactionAttributeSource)被注入到了一个名为BeanFactoryTransactionAttributeSourceAdvisor这个bean中。这个类实现了Advisor接口。只要类或方法实现了@Transactional接口,该Advisor一定会被加到拦截器链中,对原方法进行事务增强。
BeanFactoryTransactionAttributeSourceAdvisor作为一个advisor,用于对事务方法进行增强。
而InfrastructureAdvisorAutoProxyCreator作为一个
AbstractAutoProxyCreator,会在getBean时调用其postProcessAfterInstantiation方法,该方法会创建事务代理。
创建事务代理是对事务方法前后添加 开启、回滚、提交事务的功能,主要依赖于TransactionInterceptor来增强事务功能。
前置知识
事务介绍
编程式事务:所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,Spring推荐使用TransactionTemplate。
声明式事务:管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。
显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。
声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。
事务传播行为
PROPAGATION_REQUIRED
如果当前存在一个事务,则加入当前事务;如果不存在任何事务,则创建一个新的事务。总之,要至少保证在一个事务中运行。PROPAGATION_REQUIRED通常作为默认的事务传播行为。
PROPAGATION_SUPPORTS
如果当前存在一个事务,则加入当前事务;如果当前不存在事务,则直接执行。 对于一些查询方法来说,PROPAGATION_SUPPORTS通常是比较合适的传播行为选择。 如果当前方法直接执行,那么不需要事务的支持;如果当前方法被其他方法调用,而其他方法启动了一个事务的时候,使用PROPAGATION_SUPPORTS可以保证当前方法能够加入当前事务并洞察当前事务对数据资源所做的更新。 比如说,A.service()会首先更新数据库,然后调用B.service()进行查询,那么,B.service()如果是PROPAGATION_SUPPORTS的传播行为, 就可以读取A.service()之前所做的最新更新结果,而如果使用稍后所提到的PROPAGATION_NOT_SUPPORTED,则B.service()将无法读取最新的更新结果,因为A.service()的事务在这个时候还没有提交(除非隔离级别是read uncommitted)。
PROPAGATION_MANDATORY
PROPAGATION_MANDATORY强制要求当前存在一个事务,如果不存在,则抛出异常。 如果某个方法需要事务支持,但自身又不管理事务提交或者回滚的时候,比较适合使用
PROPAGATION_MANDATORY。
PROPAGATION_REQUIRES_NEW
不管当前是否存在事务,都会创建新的事务。如果当前存在事务的话,会将当前的事务挂起(suspend)。 如果某个业务对象所做的事情不想影响到外层事务的话,PROPAGATION_REQUIRES_NEW应该是合适的选择,比如,假设当前的业务方法需要向数据库中更新某些日志信息, 但即使这些日志信息更新失败,我们也不想因为该业务方法的事务回滚而影响到外层事务的成功提交,因为这种情况下,当前业务方法的事务成功与否对外层事务来说是无关紧要的。
PROPAGATION_NOT_SUPPORTED
不支持当前事务,而是在没有事务的情况下执行。如果当前存在事务的话,当前事务原则上将被挂起(suspend),但要依赖于对应的PlatformTransactionManager实现类是否支持事务的挂起(suspend),更多情况请参照TransactionDefinition的javadoc文档。 PROPAGATION_NOT_SUPPORTED与PROPAGATION_SUPPORTS之间的区别,可以参照PROPAGATION_SUPPORTS部分的实例内容。
PROPAGATION_NEVER
永远不需要当前存在事务,如果存在当前事务,则抛出异常。
PROPAGATION_NESTED
如果存在当前事务,则在当前事务的一个嵌套事务中执行,否则与PROPAGATION_REQUIRED的行为类似,即创建新的事务,在新创建的事务中执行。 PROPAGATION_NESTED粗看起来好像与PROPAGATION_REQUIRES_NEW的行为类似,实际上二者是有差别的。 PROPAGATION_REQUIRES_NEW创建的新事务与外层事务属于同一个“档次”,即二者的地位是相同的,当新创建的事务运行的时候,外层事务将被暂时挂起(suspend); 而PROPAGATION_NESTED创建的嵌套事务则不然,它是寄生于当前外层事务的,它的地位比当前外层事务的地位要小一号,当内部嵌套事务运行的时候,外层事务也是处于active状态。
解析事务标签
<tx:annotation-driven />
同AOP标签,需要一个对应的BeanDefinitionParser。
AnnotationDrivenBeanDefinitionParser.parse
public BeanDefinition parse(Element element, ParserContext parserContext) { registerTransactionalEventListenerFactory(parserContext); String mode = element.getAttribute("mode"); if ("aspectj".equals(mode)) { // mode="aspectj" registerTransactionAspect(element, parserContext); } else { // mode="proxy" AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext); } return null;}
AopAutoProxyConfigurer.configureAutoProxyCreator
逻辑:
注册了一个creator和三个bean。这三个bean支撑起了整个的事务功能。
其中的两个bean(TransactionInterceptor和AnnotationTransactionAttributeSource)被注入到了一个名为BeanFactoryTransactionAttributeSourceAdvisor这个bean中。
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {// 注册InfrastructureAdvisorAutoProxyCreator这个类 AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element); String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME; if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) { Object eleSource = parserContext.extractSource(element); // Create the TransactionAttributeSource definition.//创建TransactionAttributeSource的beanRootBeanDefinition sourceDef = new RootBeanDefinition( "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"); sourceDef.setSource(eleSource); sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);// 注册bean,并使用Spring中的定义规则生成beanName String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef); // 创建TransactionInterceptor的bean RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class); interceptorDef.setSource(eleSource); interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registerTransactionManager(element, interceptorDef); interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));// 注册bean,并使用Spring中的定义规则生成beanName String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef); // Create the TransactionAttributeSourceAdvisor definition. // 创建TransactionAttributeSourceAdvisor的beanRootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class); advisorDef.setSource(eleSource); advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);// 将sourceName的bean注入advisorDef的transactionAttributeSource advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));// 将interceptorName的bean注入advisorDef的adviceBeanName advisorDef.getPropertyValues().add("adviceBeanName", interceptorName); if (element.hasAttribute("order")) { advisorDef.getPropertyValues().add("order", element.getAttribute("order")); } parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef); CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource); compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName)); compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName)); compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName)); parserContext.registerComponent(compositeDef); }}
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary
public static void registerAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) { BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement)); useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); registerComponentIfNecessary(beanDefinition, parserContext);}
AopConfigUtils.registerAutoProxyCreatorIfNecessary
这里注册了InfrastructureAdvisorAutoProxyCreator(基础设施)这个类。
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) { return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);}
BeanFactoryTransactionAttributeSourceAdvisor(用于对事务方法进行增强)
在AOP的BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans中获取了所有类型为Advisor的bean,包括BeanFactoryTransactionAttributeSourceAdvisor这个类,并随着其他的Advisor一起在后续的步骤中被织入代理。
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { private TransactionAttributeSource transactionAttributeSource; private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { @Override protected TransactionAttributeSource getTransactionAttributeSource() { return transactionAttributeSource; } }; /** * Set the transaction attribute source which is used to find transaction * attributes. This should usually be identical to the source reference * set on the transaction interceptor itself. * @see TransactionInterceptor#setTransactionAttributeSource */ public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) { this.transactionAttributeSource = transactionAttributeSource; } /** * Set the {@link ClassFilter} to use for this pointcut. * Default is {@link ClassFilter#TRUE}. */ public void setClassFilter(ClassFilter classFilter) { this.pointcut.setClassFilter(classFilter); } @Override public Pointcut getPointcut() { return this.pointcut; }}
与IOC的衔接
InfrastructureAdvisorAutoProxyCreator作为一个AbstractAutoProxyCreator,会在getBean时调用其postProcessAfterInstantiation方法,该方法会创建事务代理。
InfrastructureAdvisorAutoProxyCreator.postProcessAfterInstantiation
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { Object cacheKey = getCacheKey(beanClass, beanName); if (beanName == null || !this.targetSourcedBeans.contains(beanName)) { if (this.advisedBeans.containsKey(cacheKey)) { return null; } if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } } // Create proxy here if we have a custom TargetSource. // Suppresses unnecessary default instantiation of the target bean: // The TargetSource will handle target instances in a custom fashion. if (beanName != null) { TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { this.targetSourcedBeans.add(beanName); Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } } return null;}
getAdvicesAndAdvisorsForBean会寻找所有实现Advisor接口的类。
我们之前注册了BeanFactoryTransactionAttributeSourceAdvisor这个类,这个类实现了Advisor接口。BeanFactoryTransactionAttributeSourceAdvisor作为一个advisor,用于对事务方法进行增强。只要类或方法实现了@Transactional接口,该Advisor一定会被加到拦截器链中,对原方法进行事务增强。
返回的Advisor类型是BeanFactoryTransactionAttributeSourceAdvisor,而其beanName是TransactionInterceptor。
之后调用了findAdvisorsThatCanApply 方法,又调用canApply方法。
1) canApply(判断bean是否需要添加事务增强)
canApply(BeanFactoryTransactionAttributeSourceAdvisor,targetClass)
关键在于是否从指定的类或类中的方法找到对应的事务属性
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {// 处理引入增强 if (advisor instanceof IntroductionAdvisor) { return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); }// 处理PointcutAdvisor,是指有切入点的Advisor else if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else {// 没有切入点的始终匹配 // It doesn't have a pointcut so we assume it applies. return true; }}
pca.getPointcut()对于BeanFactoryTransactionAttributeSourceAdvisor而言,是TransactionAttributeSourcePointcut。
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { @Override protected TransactionAttributeSource getTransactionAttributeSource() { return transactionAttributeSource; }};
pc.getMethodMatcher()对于TransactionAttributeSourcePointcut而言,就是this。
public final MethodMatcher getMethodMatcher() { return this;}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null"); if (!pc.getClassFilter().matches(targetClass)) { return false; } MethodMatcher methodMatcher = pc.getMethodMatcher(); if (methodMatcher == MethodMatcher.TRUE) { // No need to iterate the methods if we're matching any method anyway... return true; } IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } // 获取bean目标类和所有接口,放到集合中 Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); classes.add(targetClass);// 遍历集合,获取每个类/接口的所有方法,并对方法进行逐个匹配 for (Class<?> clazz : classes) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); for (Method method : methods) { if ((introductionAwareMethodMatcher != null && introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) || // 实际的匹配方法 methodMatcher.matches(method, targetClass)) { return true; } } } return false;}
methodMatcher.matches(method, targetClass)会使用
TransactionAttributeSourcePointcut类的matches方法。
1.1) matches(匹配方法)
这里的tas就是TransactionAttributeSource。
如果该bean的该方法中存在事务属性,那么该类/方法需要继续事务增强。
public boolean matches(Method method, Class<?> targetClass) { if (TransactionalProxy.class.isAssignableFrom(targetClass)) { return false; } TransactionAttributeSource tas = getTransactionAttributeSource(); return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);}
1.1.1) AnnotationTransactionAttributeSource.getTransactionAttribute(获取事务属性,封装了@Transactional中的配置信息)
先尝试从缓存加载,如果对应信息没有被缓存的话,工作又委托给了computeTransactionAttribute方法。
public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) { if (method.getDeclaringClass() == Object.class) { return null; } // First, see if we have a cached value. Object cacheKey = getCacheKey(method, targetClass); Object 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 (TransactionAttribute) 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.isDebugEnabled()) { logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr); } this.attributeCache.put(cacheKey, txAttr); } return txAttr; }}
1.1.1.1) computeTransactionAttribute(提取事务注解)
逻辑:如果方法中存在事务属性,则使用方法上的属性,否则使用方法所在的类上的属性。如果方法所在类的属性上还是没有搜寻到对应的事务属性,那么再搜寻接口中的方法,再没有的话,最后尝试搜寻接口的类上面的声明。
protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) { // Don't allow no-public methods as required. if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } // Ignore CGLIB subclasses - introspect the actual user class. Class<?> userClass = ClassUtils.getUserClass(targetClass); // 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代表实现类中的方法 Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass); // If we are dealing with method with generic parameters, find the original method. specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); // 查看方法中是否存在事务声明 // 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;}
protected TransactionAttribute findTransactionAttribute(Method method) { return determineTransactionAttribute(method);}
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) { if (ae.getAnnotations().length > 0) { for (TransactionAnnotationParser annotationParser : this.annotationParsers) { TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae); if (attr != null) { return attr; } } } return null;}
1.1.1.1.1) TransactionAnnotationParser.parseTransactionAnnotation(解析注解)
以SpringTransactionAnnotationParser为例:
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {//寻找@Transactional注解,有则解析该注解 AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class); if (attributes != null) { return parseTransactionAnnotation(attributes); } else { return null; }}
解析@Transactional中的各个属性,并封装到TransactionAttribute中返回。
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")); ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>(); Class<?>[] rbf = attributes.getClassArray("rollbackFor"); for (Class<?> rbRule : rbf) { RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule); rollBackRules.add(rule); } String[] rbfc = attributes.getStringArray("rollbackForClassName"); for (String rbRule : rbfc) { RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule); rollBackRules.add(rule); } Class<?>[] nrbf = attributes.getClassArray("noRollbackFor"); for (Class<?> rbRule : nrbf) { NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule); rollBackRules.add(rule); } String[] nrbfc = attributes.getStringArray("noRollbackForClassName"); for (String rbRule : nrbfc) { NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule); rollBackRules.add(rule); } rbta.getRollbackRules().addAll(rollBackRules); return rbta;}
创建事务代理
重要类/接口介绍
PlatformTransactionManager
public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException;}
getTransaction():返回一个已经激活的事务或创建一个新的事务(根据给定的TransactionDefinition类型参数定义的事务属性),返回的是TransactionStatus对象代表了当前事务的状态,其中该方法抛出TransactionException(未检查异常)表示事务由于某种原因失败。
commit():用于提交TransactionStatus参数代表的事务
rollback():用于回滚TransactionStatus参数代表的事务
TransactionSynchronizationManager(持有一系列事务相关的ThreadLocal对象)
public abstract class TransactionSynchronizationManager { private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<Map<Object, Object>>("Transactional resources"); private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations = new NamedThreadLocal<Set<TransactionSynchronization>>("Transaction synchronizations"); private static final ThreadLocal<String> currentTransactionName = new NamedThreadLocal<String>("Current transaction name"); private static final ThreadLocal<Boolean> currentTransactionReadOnly = new NamedThreadLocal<Boolean>("Current transaction read-only status"); private static final ThreadLocal<Integer> currentTransactionIsolationLevel = new NamedThreadLocal<Integer>("Current transaction isolation level"); private static final ThreadLocal<Boolean> actualTransactionActive = new NamedThreadLocal<Boolean>("Actual transaction active");}
getResource(获取当前线程绑定的连接)
public static Object getResource(Object key) { Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key); Object value = doGetResource(actualKey); if (value != null && logger.isTraceEnabled()) { logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]"); } return value;}
private static Object doGetResource(Object actualKey) { Map<Object, Object> map = resources.get(); if (map == null) { return null; } Object value = map.get(actualKey); // Transparently remove ResourceHolder that was marked as void... if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) { map.remove(actualKey); // Remove entire ThreadLocal if empty... if (map.isEmpty()) { resources.remove(); } value = null; } return value;}
bindResouce(将新连接绑定到当前线程)
public static void bindResource(Object key, Object value) throws IllegalStateException { Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key); Assert.notNull(value, "Value must not be null"); Map<Object, Object> map = resources.get(); // set ThreadLocal Map if none found if (map == null) { map = new HashMap<Object, Object>(); resources.set(map); } Object oldValue = map.put(actualKey, value); // Transparently suppress a ResourceHolder that was marked as void... if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) { oldValue = null; } if (oldValue != null) { throw new IllegalStateException("Already value [" + oldValue + "] for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]"); } if (logger.isTraceEnabled()) { logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" + Thread.currentThread().getName() + "]"); }}
unbindResource(释放当前线程绑定的连接)
public static Object unbindResource(Object key) throws IllegalStateException { Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key); Object value = doUnbindResource(actualKey); if (value == null) { throw new IllegalStateException( "No value for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]"); } return value;}
setActualTransactionActive(设置当前线程存在事务)
public static void setActualTransactionActive(boolean active) { actualTransactionActive.set(active ? Boolean.TRUE : null);}
setCurrentTransactionIsolationLevel(设置当前线程对应事务的隔离级别)
public static void setCurrentTransactionIsolationLevel(Integer isolationLevel) { currentTransactionIsolationLevel.set(isolationLevel);}
isSynchronizationActive(当前线程对应的事务synchronization不为空)
public static boolean isSynchronizationActive() { return (synchronizations.get() != null);}
initSynchronization(初始化当前线程的synchronization)
public static void initSynchronization() throws IllegalStateException { if (isSynchronizationActive()) { throw new IllegalStateException("Cannot activate transaction synchronization - already active"); } logger.trace("Initializing transaction synchronization"); synchronizations.set(new LinkedHashSet<TransactionSynchronization>());}
clearSynchronization(清空当前线程的synchronization)
public static void clearSynchronization() throws IllegalStateException { if (!isSynchronizationActive()) { throw new IllegalStateException("Cannot deactivate transaction synchronization - not active"); } logger.trace("Clearing transaction synchronization"); synchronizations.remove();}
TransactionStatus(事务状态)
public interface TransactionStatus extends SavepointManager, Flushable { boolean isNewTransaction(); boolean hasSavepoint(); void setRollbackOnly(); boolean isRollbackOnly(); @Override void flush(); boolean isCompleted();}
DefaultTransactionStatus是其实现类
isNewTransaction(是否是新事务)
public boolean isNewTransaction() { return (hasTransaction() && this.newTransaction);}
hasTransaction(是否有事务)
public boolean hasTransaction() { return (this.transaction != null);}
isReadOnly(是否是只读事务)
public boolean isReadOnly() { return this.readOnly;}
isGlobalRollbackOnly(是否是rollback-only)
public boolean isGlobalRollbackOnly() { return ((this.transaction instanceof SmartTransactionObject) && ((SmartTransactionObject) this.transaction).isRollbackOnly());}
与AOP的衔接
ReflectiveMethodInvocation.proceed(执行拦截器链的方法)
其中调用了MethodInterceptor.invoke()拦截器方法。
对于标记了@Transactional的方法而言,会被代理,增强事务功能。
这些方法的Advisor增强中包括了TransactionInterceptor
(BeanFactoryTransactionAttributeSourceAdvisor对应的bean)。
TransactionInterceptor支撑着整个事务功能的架构,它继承了MethodInterceptor。
public Object proceed() throws Throwable {// 执行完所有增强后,执行切点方法(method.invoke()) // We start with an index of -1 and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // 获取下一个要执行的拦截器 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// 动态匹配 // Evaluate dynamic method matcher here: static part will already have // been evaluated and found to match. InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else {// 不匹配则不执行拦截器,递归调用自己,执行下一个拦截器 // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. return proceed(); } } else {// 若为普通拦截器则直接调用拦截器 // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); }}
TransactionInterceptor.invoke(事务增强)
public Object invoke(final 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, new InvocationCallback() { @Override public Object proceedWithInvocation() throws Throwable { return invocation.proceed(); } });}
TransactionAspectSupport.invokeWithinTransaction
逻辑:
1)获取事务属性
2)加载配置中的TransactionManager
3)不同的事务处理方式使用不同的逻辑。
声明式事务和编程式事务的区别:
①区别在于事务属性上,因为编程式的事务处理是不需要有事务属性的
②区别在于TransactionManager上,CallbackPreferringPlatformTransactionManager实现PlatformTransactionManager接口,暴露出一个方法用于执行事务处理的回调。
4)在目标方法执行前获取事务并收集事务信息
事务信息(TransactionInfo)与事务属性(TransactionAttribute)并不相同。
前者包含了后者,且包含了其他事务信息,比如PlatformTransactionManager以及TransactionStatus相关信息。
TransactionAspectSupport.invokeWithinTransaction逻辑:1)获取事务属性2)加载配置中的TransactionManager3)不同的事务处理方式使用不同的逻辑。声明式事务和编程式事务的区别:①区别在于事务属性上,因为编程式的事务处理是不需要有事务属性的②区别在于TransactionManager上,CallbackPreferringPlatformTransactionManager实现PlatformTransactionManager接口,暴露出一个方法用于执行事务处理的回调。4)在目标方法执行前获取事务并收集事务信息事务信息(TransactionInfo)与事务属性(TransactionAttribute)并不相同。前者包含了后者,且包含了其他事务信息,比如PlatformTransactionManager以及TransactionStatus相关信息。
1)createTransactionIfNecessary(创建事务)
逻辑:
1)使用DelegatingTransactionAttribute封装传入的TransactionAttribute。
TransactionAttribute在这里的实际类型是RuleBasedTransactionAttribute,是由获取事务属性时生成,主要用于数据承载,使用DelegatingTransactionAttribute承载可以提供更多的功能。
2)获取事务
3)构建事务信息
protected TransactionInfo createTransactionIfNecessary( PlatformTransactionManager tm, TransactionAttribute txAttr, final String joinpointIdentification) { // If no name specified, apply method identification as transaction name.// 如果没有指定名称,则使用方法唯一标识,并使用DelegatingTransactionAttribute封装TransactionAttribute 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) {// 创建事务,返回TransactionStatus status = tm.getTransaction(txAttr); } else { if (logger.isDebugEnabled()) { logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured"); } } }// 根据指定的属性与status准备一个TransactionInfo return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);}
1.1)getTransaction(开启事务,返回TransactionStatus)
逻辑:
1)获取事务,创建对应的事务实例
2)如果当前线程存在事务,那么转向嵌套事务的处理
3)事务超时的验证
4)事务传播行为的验证
5)构建DefaultTransactionStatus
6)完善transaction,包括设置ConnectionHolder、隔离级别、timeout,如果是新连接,则绑定到当前线程
7)将事务信息记录在当前线程中。
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { Object transaction = doGetTransaction(); // Cache debug flag to avoid repeated checks. boolean debugEnabled = logger.isDebugEnabled(); if (definition == null) { // Use defaults if no transaction definition given. definition = new DefaultTransactionDefinition(); } // 判断当前线程是否存在事务,依据(DataSourceTransactionManager)是当前线程记录的连接connectionHolder不为空,且connectionHolder中的transactionActive属性为true if (isExistingTransaction(transaction)) { // Existing transaction found -> check propagation behavior to find out how to behave.// 当前线程已存在事务,根据传播行为进行相应的处理,直接返回 return handleExistingTransaction(definition, transaction, debugEnabled); }// 当前线程不存在事务 // 事务超时的验证 // Check definition settings for new transaction. if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) { throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout()); } // No existing transaction found -> check propagation behavior to find out how to proceed. // 事务传播行为的验证// 当前线程不存在事务,但是传播行为却被声明为PROPAGATION_MANDATORY(支持当前事务,如果当前没有事务,就抛出异常),则抛出异常 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) { throw new IllegalTransactionStateException( "No existing transaction found for transaction marked with propagation 'mandatory'"); } else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {// 当前线程没有事务,且传播行为是以上传播行为,那么空挂起// 考虑到如果有注册的Synchronization的话,需要暂时将这些与将要开启的新事务无关的Synchronization先放一边。// 剩下的其他情况,则返回不包含任何transaction object的TransactionStatus并返回// 这种情况下虽然是空的事务,但有可能需要处理在事务过程中相关的Synchronization。 SuspendedResourcesHolder suspendedResources = suspend(null); if (debugEnabled) { logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition); } try { boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);// 创建当前事务的状态 DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);// 完善事务,包括设置ConnectionHolder、隔离级别、timeout// 另外如果是新连接,绑定到当前线程 doBegin(transaction, definition);// 将事务信息记录在当前线程中 prepareSynchronization(status, definition); return status; } catch (RuntimeException ex) { resume(null, suspendedResources); throw ex; } catch (Error err) { resume(null, suspendedResources); throw err; } } else { // Create "empty" transaction: no actual transaction, but potentially synchronization. if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) { logger.warn("Custom isolation level specified but no actual transaction initiated; " + "isolation level will effectively be ignored: " + definition); } boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null); }}
1.1.1) doGetTransaction(创建事务实例)
DataSourceTransactionManager.doGetTransaction
protected Object doGetTransaction() { DataSourceTransactionObject txObject = new DataSourceTransactionObject(); txObject.setSavepointAllowed(isNestedTransactionAllowed());// 如果当前线程已经记录数据库连接,则使用原有连接 ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);txObject.setConnectionHolder(conHolder, false); return txObject;}
1.1.1.1) DataSourceTransactionObject.setConnectionHolder
public void setConnectionHolder(ConnectionHolder connectionHolder, boolean newConnectionHolder) { super.setConnectionHolder(connectionHolder); this.newConnectionHolder = newConnectionHolder;}
1.1.2) handleExistingTransaction (处理已存在的事务)
值得注意的有两点:
1)REQUIRES_NEW表示当前方法必须在它自己的事务里运行,一个新的事务将被启动。而如果有一个事务正在运行的话,则在这个方法运行期间被挂起(suspend)。
2)NESTED表示如果当前正在有一个事务在运行中,则该方法应该运行在一个嵌套的事务中,被嵌套的事务可以独立于封装事务进行提交或者回滚。如果封装事务不存在,行为就像REQUIRES_NEW。
Spring主要有两种处理NESTED的方式:
①首选设置保存点的方式作为异常处理的回滚
②JTA无法使用保存点,那么处理方式和REQUIRES_NEW相同,而一旦出现异常,则由Spring的事务异常处理机制去完成后续操作。
private TransactionStatus handleExistingTransaction( TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException { if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) { throw new IllegalTransactionStateException( "Existing transaction found for transaction marked with propagation 'never'"); } if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) { if (debugEnabled) { logger.debug("Suspending current transaction"); } Object suspendedResources = suspend(transaction); boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); return prepareTransactionStatus( definition, null, false, newSynchronization, debugEnabled, suspendedResources); } if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) { if (debugEnabled) { logger.debug("Suspending current transaction, creating new transaction with name [" + definition.getName() + "]"); } SuspendedResourcesHolder suspendedResources = suspend(transaction); try { boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); doBegin(transaction, definition); prepareSynchronization(status, definition); return status; } catch (RuntimeException beginEx) { resumeAfterBeginException(transaction, suspendedResources, beginEx); throw beginEx; } catch (Error beginErr) { resumeAfterBeginException(transaction, suspendedResources, beginErr); throw beginErr; } } if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { if (!isNestedTransactionAllowed()) { throw new NestedTransactionNotSupportedException( "Transaction manager does not allow nested transactions by default - " + "specify 'nestedTransactionAllowed' property with value 'true'"); } if (debugEnabled) { logger.debug("Creating nested transaction with name [" + definition.getName() + "]"); } if (useSavepointForNestedTransaction()) { // Create savepoint within existing Spring-managed transaction, // through the SavepointManager API implemented by TransactionStatus. // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization. DefaultTransactionStatus status = prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null); status.createAndHoldSavepoint(); return status; } else { // Nested transaction through nested begin and commit/rollback calls. // Usually only for JTA: Spring synchronization might get activated here // in case of a pre-existing JTA transaction. boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, null); doBegin(transaction, definition); prepareSynchronization(status, definition); return status; } } // 处理SUPPORTS和REQUIRED // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED. if (debugEnabled) { logger.debug("Participating in existing transaction"); } if (isValidateExistingTransaction()) { if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) { Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel(); if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) { Constants isoConstants = DefaultTransactionDefinition.constants; throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] specifies isolation level which is incompatible with existing transaction: " + (currentIsolationLevel != null ? isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) : "(unknown)")); } } if (!definition.isReadOnly()) { if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) { throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] is not marked as read-only but existing transaction is"); } } } boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);}
1.1.3) suspend(null->doNothing)
如果当前线程不存在事务,并且事务传播行为是Required、Required_New、Nested,那么执行suspend(null)。
考虑到如果有注册的synchronization的话,需要暂时将这些与将要开启的新事务无关的synchronization先放一边。
正常的suspend是记录原有事务的状态,以便后续操作对事务的恢复(TransactionSynchronizationManager.unBindResource)
protected final SuspendedResourcesHolder suspend(Object transaction) throws TransactionException { if (TransactionSynchronizationManager.isSynchronizationActive()) { List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization(); try { Object suspendedResources = null; if (transaction != null) { suspendedResources = doSuspend(transaction); } String name = TransactionSynchronizationManager.getCurrentTransactionName(); TransactionSynchronizationManager.setCurrentTransactionName(null); boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly(); TransactionSynchronizationManager.setCurrentTransactionReadOnly(false); Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel(); TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null); boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive(); TransactionSynchronizationManager.setActualTransactionActive(false); return new SuspendedResourcesHolder( suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive); } catch (RuntimeException ex) { // doSuspend failed - original transaction is still active... doResumeSynchronization(suspendedSynchronizations); throw ex; } catch (Error err) { // doSuspend failed - original transaction is still active... doResumeSynchronization(suspendedSynchronizations); throw err; } } else if (transaction != null) { // Transaction active but no synchronization active. Object suspendedResources = doSuspend(transaction); return new SuspendedResourcesHolder(suspendedResources); } else { // Neither transaction nor synchronization active. return null; }}
1.1.3.1) doSuspendSynchronization
private List<TransactionSynchronization> doSuspendSynchronization() { List<TransactionSynchronization> suspendedSynchronizations = TransactionSynchronizationManager.getSynchronizations(); for (TransactionSynchronization synchronization : suspendedSynchronizations) { synchronization.suspend(); }// 清空synchronization TransactionSynchronizationManager.clearSynchronization(); return suspendedSynchronizations;}
1.1.4) newTransactionStatus (创建当前事务的状态)
boolean newSynchronization = (getTransactionSynchronization() !=
SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);
新事务则传入的newTransaction为true,否则为false
definition.isReadOnly()返回的是@Transactional中的属性,默认为false。
protected DefaultTransactionStatus newTransactionStatus( TransactionDefinition definition, Object transaction, boolean newTransaction, boolean newSynchronization, boolean debug, Object suspendedResources) { boolean actualNewSynchronization = newSynchronization && !TransactionSynchronizationManager.isSynchronizationActive(); return new DefaultTransactionStatus( transaction, newTransaction, actualNewSynchronization, definition.isReadOnly(), debug, suspendedResources);}
理解newTransaction
newTransaction标识该切面方法是否新建了事务,后续切面方法执行完毕时,通过该字段判断是否 需要提交事务或者回滚事务。
1.1.5) doBegin(完善事务实例)
逻辑:
1)尝试获取连接。如果当前线程中的connectionHolder已经存在,则没有必要再次获取;对于事务同步设置为true的需要重新获取连接
2)设置隔离级别以及只读标识
3)更改默认的提交设置,将提交操作委托给Spring来处理
4)设置标志位,标识当前连接已经被事务激活
5)设置超时时间
6)如果是新连接,则将connectionHolder绑定到当前线程
protected void doBegin(Object transaction, TransactionDefinition definition) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; Connection con = null; try { if (txObject.getConnectionHolder() == null || txObject.getConnectionHolder().isSynchronizedWithTransaction()) { Connection newCon = this.dataSource.getConnection(); if (logger.isDebugEnabled()) { logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction"); }// 设置ConnectionHolder txObject.setConnectionHolder(new ConnectionHolder(newCon), true); } txObject.getConnectionHolder().setSynchronizedWithTransaction(true); con = txObject.getConnectionHolder().getConnection();// 设置隔离级别 Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);txObject.setPreviousIsolationLevel(previousIsolationLevel); // Switch to manual commit if necessary. This is very expensive in some JDBC drivers, // so we don't want to do it unnecessarily (for example if we've explicitly // configured the connection pool to set it already).// 更改自动提交设置,由Spring控制提交 if (con.getAutoCommit()) { txObject.setMustRestoreAutoCommit(true); if (logger.isDebugEnabled()) { logger.debug("Switching JDBC Connection [" + con + "] to manual commit"); } con.setAutoCommit(false); } prepareTransactionalConnection(con, definition);// 设置判断当前线程是否存在事务的依据,即transactionActive txObject.getConnectionHolder().setTransactionActive(true); int timeout = determineTimeout(definition); if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {//设置timeout属性 txObject.getConnectionHolder().setTimeoutInSeconds(timeout); } // Bind the connection holder to the thread.// 如果是新的连接,则将当前获取到的连接绑定到当前线程 if (txObject.isNewConnectionHolder()) { TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder()); } } catch (Throwable ex) { if (txObject.isNewConnectionHolder()) { DataSourceUtils.releaseConnection(con, this.dataSource); txObject.setConnectionHolder(null, false); } throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex); }}
1.1.6) prepareSynchronization(记录事务信息至当前线程)
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) { if (status.isNewSynchronization()) { TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction()); TransactionSynchronizationManager.setCurrentTransactionIsolationLevel( definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ? definition.getIsolationLevel() : null); TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly()); TransactionSynchronizationManager.setCurrentTransactionName(definition.getName()); TransactionSynchronizationManager.initSynchronization(); }}
1.2) prepareTransactionInfo(构建事务信息)
当已经建立事务连接并完成了事务信息的提取后,需要将所有的事务信息统一记录在TransactionInfo实例中,这个实例包含了目标方法开始前的所有状态信息。一旦事务执行失败,Spring会通过TransactionInfo实例来进行回滚等后续工作。
protected TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm, TransactionAttribute txAttr, String joinpointIdentification, 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("Don't need to create transaction for [" + joinpointIdentification + "]: This method isn't 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;}
2)completeTransactionAfterThrowing (回滚事务)
protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {// 当抛出异常时首先判断当前是否存在事务,这是基础依据 if (txInfo != null && txInfo.hasTransaction()) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex); }// 判断是否回滚 默认的依据是 抛出的异常是否是RuntimeException或者是Error的类型 if (txInfo.transactionAttribute.rollbackOn(ex)) { try { // 根据TransactionStatus信息进行回滚处理 txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by rollback exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException ex2) { logger.error("Application exception overridden by rollback exception", ex); throw ex2; } catch (Error err) { logger.error("Application exception overridden by rollback error", ex); throw err; } } 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 ex2) { logger.error("Application exception overridden by commit exception", ex); throw ex2; } catch (Error err) { logger.error("Application exception overridden by commit error", ex); throw err; } } }}
2.1) TransactionAttribute.rollbackOn(判断是否需要回滚)
DefaultTransactionAttribute的实现是
public boolean rollbackOn(Throwable ex) { return (ex instanceof RuntimeException || ex instanceof Error);}
RuleBasedTransactionAttribute的实现是
public boolean rollbackOn(Throwable ex) { if (logger.isTraceEnabled()) { logger.trace("Applying rules to determine whether transaction should rollback on " + ex); } RollbackRuleAttribute winner = null; int deepest = Integer.MAX_VALUE; if (this.rollbackRules != null) { for (RollbackRuleAttribute rule : this.rollbackRules) { int depth = rule.getDepth(ex); if (depth >= 0 && depth < deepest) { deepest = depth; winner = rule; } } } if (logger.isTraceEnabled()) { logger.trace("Winning rollback rule is: " + winner); } // User superclass behavior (rollback on unchecked) if no rule matches. if (winner == null) { logger.trace("No relevant rollback rule found: applying default rules"); return super.rollbackOn(ex); } return !(winner instanceof NoRollbackRuleAttribute);}
2.2) 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);}
processRollback
1)首先是自定义触发器的调用,包括在回滚前、完成回滚后的调用,当然完成回滚包括正常回滚与回滚过程中出现异常,自定义的触发器会根据这些信息做进一步处理,而对于触发器的注册,常见是在回调过程过程中提供TransactionSynchronizationManager类中的静态方法直接注册。
public static void registerSynchronization(TransactionSynchronization synchronization)
2)除了触发监听函数外,就是真正的回滚逻辑处理了。有保存点则回滚到保存点,是新事务则回滚整个事务;存在事务又不是新事务,则做回滚标记。
3)回滚后进行信息清除
private void processRollback(DefaultTransactionStatus status) { try { try { // 激活所有TransactionSynchronization中对应的beforeCompletion方法 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 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"); } } catch (RuntimeException ex) { triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN); throw ex; } catch (Error err) { triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN); throw err; } // 激活所有TransactionSynchronization中对应的方法 triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK); } finally { // 清空记录的资源并将挂起的资源恢复 cleanupAfterCompletion(status); }}
2.2.1) triggerBeforeCompletion(调用触发器)
protected final void triggerBeforeCompletion(DefaultTransactionStatus status) { if (status.isNewSynchronization()) { if (status.isDebug()) { logger.trace("Triggering beforeCompletion synchronization"); } TransactionSynchronizationUtils.triggerBeforeCompletion(); }}
TransactionSynchronizationUtils.triggerBeforeCompletion()
public static void triggerBeforeCompletion() { for (TransactionSynchronization synchronization : TransactionSynchronizationManager.getSynchronizations()) { try { synchronization.beforeCompletion(); } catch (Throwable tsex) { logger.error("TransactionSynchronization.beforeCompletion threw exception", tsex); } }}
2.2.2) rollbackToHeldSavepoint(回滚至保存点)
public void rollbackToHeldSavepoint() throws TransactionException { if (!hasSavepoint()) { throw new TransactionUsageException( "Cannot roll back to savepoint - no savepoint associated with current transaction"); } getSavepointManager().rollbackToSavepoint(getSavepoint()); getSavepointManager().releaseSavepoint(getSavepoint()); setSavepoint(null);}
JdbcTransactionObjectSupport.rollbackToSavepoint
public void rollbackToSavepoint(Object savepoint) throws TransactionException { ConnectionHolder conHolder = getConnectionHolderForSavepoint(); try { conHolder.getConnection().rollback((Savepoint) savepoint); } catch (Throwable ex) { throw new TransactionSystemException("Could not roll back to JDBC savepoint", ex); }}
2.2.3) 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); }}
2.2.4) doSetRollbackOnly(设置回滚标记)
protected void doSetRollbackOnly(DefaultTransactionStatus status) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction(); if (status.isDebug()) { logger.debug("Setting JDBC transaction [" + txObject.getConnectionHolder().getConnection() + "] rollback-only"); } txObject.setRollbackOnly();}public void setRollbackOnly() { this.rollbackOnly = true;}
2.2.5) triggerAfterCompletion(调用触发器)
private void triggerAfterCompletion(DefaultTransactionStatus status, int completionStatus) { if (status.isNewSynchronization()) { List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations(); TransactionSynchronizationManager.clearSynchronization(); if (!status.hasTransaction() || status.isNewTransaction()) { if (status.isDebug()) { logger.trace("Triggering afterCompletion synchronization"); } // No transaction or new transaction for the current scope -> // invoke the afterCompletion callbacks immediately invokeAfterCompletion(synchronizations, completionStatus); } else if (!synchronizations.isEmpty()) { // Existing transaction that we participate in, controlled outside // of the scope of this Spring transaction manager -> try to register // an afterCompletion callback with the existing (JTA) transaction. registerAfterCompletionWithExistingTransaction(status.getTransaction(), synchronizations); } }}
2.2.6) cleanupAfterCompletion(回滚后清除信息)
逻辑:
1)设置状态是对事务信息做完成标识以避免重复调用
2)如果当前事务是新的同步状态,需要将绑定到当前线程的事务信息清除
3)如果是新事务需要做些清除资源的工作
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"); }// 结束之前事务的挂起状态 resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources()); }}
2.2.6.1) doCleanupAfterCompletion(新事务则释放资源)
protected void doCleanupAfterCompletion(Object transaction) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;// 将连接从当前线程中解除绑定 // Remove the connection holder from the thread, if exposed. if (txObject.isNewConnectionHolder()) { TransactionSynchronizationManager.unbindResource(this.dataSource); } // Reset connection. Connection con = txObject.getConnectionHolder().getConnection(); try { if (txObject.isMustRestoreAutoCommit()) { con.setAutoCommit(true); }// 重置数据库连接 DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel()); } 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();}
2.2.6.2) resume(将挂起事务恢复)
如果在事务执行前有事务挂起,那么当前事务执行结束后需要将挂起事务恢复
protected final void resume(Object transaction, 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); } }}
3)commitTransactionAfterReturning(提交事务)
protected void commitTransactionAfterReturning(TransactionInfo txInfo) { if (txInfo != null && txInfo.hasTransaction()) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]"); } txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); }}
commit
某个事务是另一个事务的嵌入事务,但是这些事务又不在Spring的管理范围之内,或者无法设置保存点,那么Spring会通过设置回滚标识的方式来禁止提交。首先当某个嵌入事务发生回滚的时候会设置回滚标识,而等到外部事务提交时,一旦判断出当前事务流被设置了回滚标识,则由外部事务来统一进行整体事务的回滚。
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); return; } if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) { if (defStatus.isDebug()) { logger.debug("Global transaction is marked as rollback-only but transactional code requested commit"); } processRollback(defStatus); // Throw UnexpectedRollbackException only at outermost transaction boundary // or if explicitly asked to. if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) { throw new UnexpectedRollbackException( "Transaction rolled back because it has been marked as rollback-only"); } return; } // 处理事务提交 processCommit(defStatus);}
processCommit
在提交过程中也不是直接提交的,而是考虑了诸多方面。
符合提交的条件如下:
当事务状态中有保存点信息的话便不会提交事务;
当事务不是新事务的时候也不会提交事务
原因是:
对于内嵌事务,在Spring中会将其在开始之前设置保存点,一旦内嵌事务出现异常便根据保存点信息进行回滚,但是如果没有出现异常,内嵌事务并不会单独提交,而是根据事务流由最外层事务负责提交,所以如果当前存在保存点信息便不是最外层事务,不做提交操作。
private void processCommit(DefaultTransactionStatus status) throws TransactionException { try { boolean beforeCompletionInvoked = false; try {// 预留 prepareForCommit(status);// 添加的TransactionSynchronization中对应方法的调用 triggerBeforeCommit(status);// 添加的TransactionSynchronization中对应方法的调用 triggerBeforeCompletion(status); beforeCompletionInvoked = true; boolean globalRollbackOnly = false; if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) { globalRollbackOnly = status.isGlobalRollbackOnly(); } if (status.hasSavepoint()) { if (status.isDebug()) { logger.debug("Releasing transaction savepoint"); }// 如果存在保存点,则清除保存点信息 status.releaseHeldSavepoint(); } else if (status.isNewTransaction()) { if (status.isDebug()) { logger.debug("Initiating transaction commit"); }// 如果是新事务,则提交 doCommit(status); } // Throw UnexpectedRollbackException if we have a global rollback-only // marker but still didn't get a corresponding exception from commit. if (globalRollbackOnly) { 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 ex) { if (!beforeCompletionInvoked) {// 添加的TransactionSynchronization中对应方法的调用 triggerBeforeCompletion(status); }// 提交过程中出现异常则回滚 doRollbackOnCommitException(status, ex); throw ex; } catch (Error err) { if (!beforeCompletionInvoked) { triggerBeforeCompletion(status); } doRollbackOnCommitException(status, err); throw err; } // Trigger afterCommit callbacks, with an exception thrown there // propagated to callers but the transaction still considered as committed. try {// 添加的TransactionSynchronization中对应方法的调用 triggerAfterCommit(status); } finally { triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED); } } finally { cleanupAfterCompletion(status); }}
运行实例
当三个事务方法(login、addUser、register)的事务传播行为为REQUIRED、REQUIRES_NEW、NESTED时,执行流程会是什么样?
REQUIRED(内层事务newTransaction为false,内层事务回滚时仅设置回滚标记,外层事务进行外层回滚)
如果几个不同的service都是共享同一个事务(也就是service对象嵌套传播机制为Propagation.REQUIRED),那么它们会一起提交,一起回滚。
同一个事务,如果一个service已经提交了,在另外service中rollback自然对第一个service提交的代码回滚不了的。所以spring处理嵌套事务,就是在TransactionInterceptor方法中,根据一系列开关(事务传播行为),来处理事务是同一个还是重新获取,如果是同一个事务,不同service的commit与rollback的时机。
这里有一个外层切面register,使用了事务,里面调用了两个service,它们也是要求使用事务的。
因为传播行为是REQUIRED,所以共用同一个事务。
当调用register时,在getTransaction时会将TransactionStatus中的newTransaction设置为true,并且将连接绑定到当前线程,设置当前线程存在事务。
当后续调用login和addUser时,它们的TransactionStatus中的newTransaction设置为false。
如果register方法中抛出运行时异常,那么直接rollback整个事务,因为它是一个新事务。
如果login方法中抛出运行时异常,只能将rollbackOnly设置为true。因为login中没有catch该异常(回滚后又抛出该异常),所以异常被register捕获(跳过了addUser),所以register又要执行rollback方法,整个事务进行回滚。
REQUIRES_NEW(内外层事务平级,内层事务newTransaction为true,suspend外层事务,抛出异常后内层事务进行内层回滚,resume外层事务,外层事务捕获到内层抛出的异常后进行外层回滚)
register创建一个事务,newTransaction为true。
调用login方法时检测到已存在事务,则将已存在事务suspend,并且创建的新事务,newTransaction为true。
当login方法抛出异常时,因为newTransaction为true,则回滚该事务。异常被抛出到外层register,register捕获该异常,并回滚。
NESTED(内外层事务嵌套,内层事务newTransaction为false,并创建还原点,抛出异常后rollback至还原点,外层事务捕获到内层抛出的异常后进行外层回滚)
如果PlatformTransactionManager支持还原点,便如上执行;如果不支持,那么行为与REQUIRES_NEW相同。
外层事务register的newTransaction为true,进入内层事务login。
内层事务login的newTransaction为false,并在获取Transaction时创建了一个还原点。(JTA不支持还原点,此时行为与REQUIRES_NEW相同)。抛出异常后在rollback时直接rollback至之前创建的还原点,并删除了该还原点。
外层事务捕获到该异常,进入rollback,因为是新事务,执行外层事务的回滚。
总结
流程图
图源网络,侵删。
个人总结
Spring Transaction可以说是Spring AOP的一个特例,AOP支持各种类型的BeanPostProcessor,而Transaction使用到了TransactionInterceptor这一特定的BeanPostProcessor,它为事务方法添加了开启、回滚、提交事务的功能。底层仍然是AOP动态代理。
- Spring Transaction 从实例读源码
- Spring IOC 从实例读源码
- Spring AOP 从实例读源码
- Spring MVC 从实例读源码
- Spring 从实例读源码系列
- Spring Transaction 源码
- spring transaction源码分析--事务架构
- spring transaction源码分析--事务架构
- spring transaction源码分析--事务架构
- spring Transaction
- spring Transaction
- SPRING TRANSACTION
- spring transaction
- Spring Transaction
- spring transaction
- spring Transaction
- spring- transaction
- Spring transaction
- 技能测试3:javascript表单验证入库
- 兄弟连学Python-MongoDB基础
- AngularJs 表单
- project euler 25 1000-digit Fibonacci number
- 3-3 构造函数的调用(高级)
- Spring Transaction 从实例读源码
- 比较计数排序和分布计数排序
- 洛谷P2590 [ZJOI2008]树的统计_树链剖分
- spring boot RESTFul API拦截 以及Filter和interceptor 、Aspect区别
- 未能映射路径“/App_GlobalResources/” 问题修复
- 凸多边形的最优三角划分最详细求解步骤演示[动态规划]
- R语言
- 小程序源代码加密,加密小程序源码方法
- 是周末啊