SpringTx 源码解析 - @Transactional 声明式事务执行原理

news2024/11/23 16:05:44

一、Spring @Transactional 声明式事务执行原理

@TransactionalSpring 框架中用于声明事务的注解,可以标注在方法或类上。当标注在类上时,表示该类的所有public方法都将支持事务。当标注在方法上时,表示该方法将在一个事务内执行。

@Transactional 的执行原理依赖于 AOP ,因此在看本篇文章时,最好对 AOP 的原理有所了解,如果不了解,可以看下下面两篇文章:

SpringAop 源码解析 (一) - Aspect 切面方法的查找匹配过程

SpringAop 源码解析 (二) - 代理对象的创建以及执行过程

下面一起开始源码的分析。

二、@EnableTransactionManagement

在普通的 Spring 项目中,开启声明式事务的支持需要使用 @EnableTransactionManagement 注解,该注解在 SpringBoot 中会自动调用,可以从该注解入手,看到底做了啥事情:

在这里插入图片描述

注意注解中代理模式默认为 PROXY ,同时还使用 @Import 引入了 TransactionManagementConfigurationSelector 类,看下该类的继承关系:

在这里插入图片描述
有实现 ImportSelector 选择注入器,因此先找到 selectImports(AnnotationMetadata importingClassMetadata) 方法,在 AdviceModeImportSelector 类下:

在这里插入图片描述

这里又使用了子类的selectImports方法的结果注入了 Spring 容器,就是TransactionManagementConfigurationSelector 类下的 selectImports 方法:

在这里插入图片描述
从上面注解中可以得到默认为 PROXY 模式,因此会注入AutoProxyRegistrarProxyTransactionManagementConfiguration 这里主要分析下 ProxyTransactionManagementConfiguration 配置类:

@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;
	}

}

该配置类中声明了三个非常重要的对象:

在这里插入图片描述
BeanFactoryTransactionAttributeSourceAdvisor :是Advisor 的子类,该类也是源码分析的关键点,由于其属于 Advisor 的子类,因此在 AOP 扫描 Advisor 增强器时会被扫描到,执行后续 AOP 的逻辑。

在这里插入图片描述

注意该类在Spring 中注册的名称为:org.springframework.transaction.config.internalTransactionAdvisor

在这里插入图片描述

TransactionAttributeSource :事务属性解析器,这里实例为 AnnotationTransactionAttributeSource ,主要在 AOP 中匹配Advisor 增强器时用到,一方面判断是否带有 @Transactional 注解,另一方面对注解中的参数进行解析包装。

在这里插入图片描述

TransactionInterceptor: 事务拦截器,是 MethodInterceptor 的子类,因此在AOP中也是最终触发执行逻辑的类,其中包含了事务的开启、提交、回滚等。

三、事务切面增强器的扫描过程

下面我们从 AOP 的执行逻辑中 AbstractAdvisorAutoProxyCreator 类下的 getAdvicesAndAdvisorsForBean 方法进行分析,主要实现了Advices 切面增强方法的扫描和匹配过程。

这里的处理过程在上篇 AOP 的文章中有分析过,因此这里主要对BeanFactoryTransactionAttributeSourceAdvisor 的扫描和匹配过程进行分析,如果对这块不了解的话,建议看下前面的 AOP 分析的文章:

下面看到该方法中:

protected Object[] getAdvicesAndAdvisorsForBean(
		Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
	//获取增强方法
	List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
	//判断是否为空
	if (advisors.isEmpty()) {
		//如果为空,返回一个空数组
		return DO_NOT_PROXY;
	}
	//如果不为空,转化为数组然后返回
	return advisors.toArray();
}

使用 findEligibleAdvisors 方法获取到匹配的增强方法,也就是切面方法,看到该方法中:

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
	//获取所有的增强方法
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	//从所有的增强方法中匹配适合该 bean 的增强方法
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	//对匹配后的增强方法进行扩展
	extendAdvisors(eligibleAdvisors);
	//判断是否为空
	if (!eligibleAdvisors.isEmpty()) {
		//如果不为空,进行排序
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
	}
	//返回处理后的增强方法
	return eligibleAdvisors;
}

这里通过 findCandidateAdvisors 方法获取到所有的切面方法,然后使用 findAdvisorsThatCanApply 方法匹配出符合该 beanName 的切面方法,首先看到 findCandidateAdvisors 方法,在 AbstractAdvisorAutoProxyCreator 类下:

在这里插入图片描述

这里又调用了 BeanFactoryAdvisorRetrievalHelper 类下的 findAdvisorBeans 方法:

public List<Advisor> findAdvisorBeans() {
	// Determine list of advisor bean names, if not cached already.
	String[] advisorNames = this.cachedAdvisorBeanNames;
	if (advisorNames == null) {
		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the auto-proxy creator apply to them!
		// 获取工厂中所有的 Advisor
		advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this.beanFactory, Advisor.class, true, false);
		this.cachedAdvisorBeanNames = advisorNames;
	}
	if (advisorNames.length == 0) {
		return new ArrayList<>();
	}

	List<Advisor> advisors = new ArrayList<>();
	for (String name : advisorNames) {
		if (isEligibleBean(name)) {
			if (this.beanFactory.isCurrentlyInCreation(name)) {
				if (logger.isTraceEnabled()) {
					logger.trace("Skipping currently created advisor '" + name + "'");
				}
			}
			else {
				try {
					// 从工厂中获取对象实例
					advisors.add(this.beanFactory.getBean(name, Advisor.class));
				}
				catch (BeanCreationException ex) {
					Throwable rootCause = ex.getMostSpecificCause();
					if (rootCause instanceof BeanCurrentlyInCreationException) {
						BeanCreationException bce = (BeanCreationException) rootCause;
						String bceBeanName = bce.getBeanName();
						if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
							if (logger.isTraceEnabled()) {
								logger.trace("Skipping advisor '" + name +
										"' with dependency on currently created bean: " + ex.getMessage());
							}
							// Ignore: indicates a reference back to the bean we're trying to advise.
							// We want to find advisors other than the currently created bean itself.
							continue;
						}
					}
					throw ex;
				}
			}
		}
	}
	return advisors;
}

这里从工厂中获取到了所有的 Advisor 类型的 beanName ,后面直接从工厂中获取到了对应的实例对象。

前面说 BeanFactoryTransactionAttributeSourceAdvisor 实现了 Advisor ,因此这里 advisors 列表中也带有 BeanFactoryTransactionAttributeSourceAdvisor 类型的实例对象。

在这里插入图片描述

四、事务切面增强器的匹配过程

下面再回到 findEligibleAdvisors 方法中,已经通过 findCandidateAdvisors 方法获取到 Advisor 切面增强方法了,下面通过 findAdvisorsThatCanApply 匹配出符合当前 beanNameAdvisor,看到该方法中:

在这里插入图片描述

这里又调用了 AopUtils.findAdvisorsThatCanApply 方法,继续看到该方法下:

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
	if (candidateAdvisors.isEmpty()) {
		return candidateAdvisors;
	}
	// 创建一个合适的 Advisor 的集合 eligibleAdvisors
	List<Advisor> eligibleAdvisors = new ArrayList<>();
	//循环所有的Advisor
	for (Advisor candidate : candidateAdvisors) {
		// 判断切面是否匹配
		//如果Advisor是 IntroductionAdvisor 引介增强 可以为目标类 通过AOP的方式添加一些接口实现
		if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
			eligibleAdvisors.add(candidate);
		}
	}
	//是否有引介增强
	boolean hasIntroductions = !eligibleAdvisors.isEmpty();
	for (Advisor candidate : candidateAdvisors) {
		//如果是IntroductionAdvisor类型的话 则直接跳过
		if (candidate instanceof IntroductionAdvisor) {
			// already processed
			continue;
		}
		// 判断切面是否匹配
		if (canApply(candidate, clazz, hasIntroductions)) {
			eligibleAdvisors.add(candidate);
		}
	}
	return eligibleAdvisors;
}

这里对 Advisor 判断是否为 IntroductionAdvisor 引介增强类型,前面看到 BeanFactoryTransactionAttributeSourceAdvisor 的继承树关系,并没有实现 IntroductionAdvisor接口 ,因此最后会使用 canApply 方法进行匹配,再看到 canApply 方法中:

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
	if (advisor instanceof IntroductionAdvisor) {
		// IntroductionAdvisor,根据类过滤器,进行匹配
		//如果是 IntroductionAdvisor 的话,则调用IntroductionAdvisor类型的实例进行类的过滤
		//这里是直接调用的ClassFilter的matches方法
		return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
	}
	// 通常情况下 Advisor 都是 PointcutAdvisor 类型
	else if (advisor instanceof PointcutAdvisor) {
		PointcutAdvisor pca = (PointcutAdvisor) advisor;
		// 从Advisor中获取Pointcut的实现类 就是是AspectJExpressionPointcut
		return canApply(pca.getPointcut(), targetClass, hasIntroductions);
	}
	else {
		// It doesn't have a pointcut so we assume it applies.
		return true;
	}
}

这里根据不同的类型走不同的匹配方式,再看下 BeanFactoryTransactionAttributeSourceAdvisor 的继承树关系,其中有实现 PointcutAdvisor 接口,因此会进入到 canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) 方法中,注意这里第一个 Pointcut 参数是通过 pca.getPointcut() 获取到的,在 BeanFactoryTransactionAttributeSourceAdvisor 中就是 TransactionAttributeSourcePointcut 对象:

在这里插入图片描述

在这里插入图片描述

下面看到 canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) 方法中:

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
	Assert.notNull(pc, "Pointcut must not be null");

	//进行切点表达式的匹配最重要的就是 ClassFilter 和 MethodMatcher这两个方法的实现。
	//首先进行ClassFilter的matches方法校验
	//首先这个类要在所匹配的规则下
	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;
	}
	// 如果当前 MethodMatcher 也是IntroductionAwareMethodMatcher类型,则转为该类型
	IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
	if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
		introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
	}

	Set<Class<?>> classes = new LinkedHashSet<>();
	if (!Proxy.isProxyClass(targetClass)) {
		// 目标对象没有采用jdk动态代理,则要么是cglib代理,要么没有代理,获取到没有代理的原始类
		classes.add(ClassUtils.getUserClass(targetClass));
	}
	// 获取到目标类的所有的超类接口
	classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

	for (Class<?> clazz : classes) {
		// 获取目标类即接口的方法,只要有一个方法满足切点条件,即视为切点可以匹配
		Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
		// 只要有一个方法能匹配到就返回true
		//MethodMatcher 中有两个 matches 方法。
		// boolean matches(Method method, Class<?> targetClass) 用于静态的方法匹配
		// boolean matches(Method method, Class<?> targetClass, Object... args) 用于运行期动态的进行方法匹配
		for (Method method : methods) {
			// 如果 MethodMatcher 是IntroductionAwareMethodMatcher类型,则使用该类型的方法进行匹配
			// 否则使用 MethodMatcher.matches() 方法进行匹配
			if (introductionAwareMethodMatcher != null ?
					introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
					methodMatcher.matches(method, targetClass)) {
				return true;
			}
		}
	}

	return false;
}

该方法首先使用 ClassFilter 对类进行匹配是否符合,如果不符合直接跳过,这里先看下 TransactionAttributeSourcePointcutgetClassFilter 获取的是哪个对象:

在这里插入图片描述

TransactionAttributeSourcePointcut 的构造函数中可以看出具体对象为 TransactionAttributeSourceClassFilter 类型,下面看到 TransactionAttributeSourceClassFilter 类下的 matches(Class<?> clazz) 方法:

public boolean matches(Class<?> clazz) {
	// 判断是否属于 TransactionalProxy 或 TransactionManager 或 PersistenceExceptionTranslator
	if (TransactionalProxy.class.isAssignableFrom(clazz) ||
			TransactionManager.class.isAssignableFrom(clazz) ||
			PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
		// 如果是返回 false 不尽兴匹配
		return false;
	}
	// 匹配判断
	TransactionAttributeSource tas = getTransactionAttributeSource();
	return (tas == null || tas.isCandidateClass(clazz));
}

这里如果是 TransactionalProxyTransactionManagerPersistenceExceptionTranslator 类直接返回 false 不进行后面的匹配,再接着获取到一个 TransactionAttributeSource 对象,从前面 ProxyTransactionManagementConfiguration 类中可以看出,主要为AnnotationTransactionAttributeSource类型实例,因此进到该类下的 isCandidateClass 方法中:

public boolean isCandidateClass(Class<?> targetClass) {
	// 遍历事务注解析器
	for (TransactionAnnotationParser parser : this.annotationParsers) {
		// 是否可解析
		if (parser.isCandidateClass(targetClass)) {
			return true;
		}
	}
	return false;
}

这里遍历了所有的事务解析器,这些解析器怎么来的呢,看到 AnnotationTransactionAttributeSource 的构造方法中:

public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
	this.publicMethodsOnly = publicMethodsOnly;
	if (jta12Present || ejb3Present) {
		this.annotationParsers = new LinkedHashSet<>(4);
		this.annotationParsers.add(new SpringTransactionAnnotationParser());
		if (jta12Present) {
			this.annotationParsers.add(new JtaTransactionAnnotationParser());
		}
		if (ejb3Present) {
			this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
		}
	}
	else {
		this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
	}
}

这里主要对 SpringTransactionAnnotationParser 类进行分析,下面可以看到 SpringTransactionAnnotationParser 类下的 isCandidateClass 方法中:

public boolean isCandidateClass(Class<?> targetClass) {
	// 检查类是否带有 @Transactional 注解
	return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}

主要就是检查类是否带有 @Transactional 注解。

下面再回到 canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) 方法中,继续向下看会通过 pc.getMethodMatcher() 获取到一个 MethodMatcher 对象,这里看下 TransactionAttributeSourcePointcut 的继承关系图:

在这里插入图片描述

可以看到 TransactionAttributeSourcePointcut 就是 MethodMatcher 类型, 但 TransactionAttributeSourcePointcut 没有重写 getMethodMatcher() 方法,实现触发的StaticMethodMatcherPointcut 类下的 getMethodMatcher() 方法:

在这里插入图片描述
这里直接返回的自身,因此这里MethodMatcher 对象就是自身 TransactionAttributeSourcePointcut

下面再回到 canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) 方法中,最后通过反射获取到类下的方法,由于这里不属于introductionAwareMethodMatcher类型,会通过 methodMatcher.matches 判断是否符合,下面看到 TransactionAttributeSourcePointcut 类下的 matches(Method method, Class<?> targetClass) 方法中:

public boolean matches(Method method, Class<?> targetClass) {
	TransactionAttributeSource tas = getTransactionAttributeSource();
	// 如果存在事务信息则返回true
	return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

上面已经分析过了 TransactionAttributeSource 主要为 AnnotationTransactionAttributeSource类型实例,因此看到该类下的 getTransactionAttribute 方法中:

主要实现在父类的 AbstractFallbackTransactionAttributeSource 类中:

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
	// 如果是 Object 类型,直接返回 null
	if (method.getDeclaringClass() == Object.class) {
		return null;
	}
	// First, see if we have a cached value.
	// 生成缓存 key
	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 dta = (DefaultTransactionAttribute) txAttr;
				dta.setDescriptor(methodIdentification);
				dta.resolveAttributeStrings(this.embeddedValueResolver);
			}
			if (logger.isTraceEnabled()) {
				logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
			}
			this.attributeCache.put(cacheKey, txAttr);
		}
		return txAttr;
	}
}

这里对事物属性进行了缓存,看下缓存中不存在的情况,通过 computeTransactionAttribute 方法,尝试解析事物属性,也就是解析 @Transactional 中的属性,下面看到该方法中:

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;
}

这里会先尝试从方法上取获取 @Transactional 注解,不存在的话再去检测方法所在类上是否符合,这里主要看下方法层面的 findTransactionAttribute(Method method) 方法:

在这里插入图片描述

这里又触发了 determineTransactionAttribute 方法,继续看到该方法中:

protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
	// 遍历事务解析器
	for (TransactionAnnotationParser parser : this.annotationParsers) {
		// 使用解析器解析事务信息
		TransactionAttribute attr = parser.parseTransactionAnnotation(element);
		if (attr != null) {
			return attr;
		}
	}
	return null;
}

这里又使用了前面提到的 TransactionAnnotationParser 解析器,还是主要看 SpringTransactionAnnotationParser,进到 SpringTransactionAnnotationParser 类下的 parseTransactionAnnotation 方法中:

public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
	// 寻找目标上的 @Transactional 注解信息
	AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
			element, Transactional.class, false, false);
	if (attributes != null) {
		// 解析注解中的参数属性,包装到  TransactionAttribute 对象中
		return parseTransactionAnnotation(attributes);
	}
	else {
		return null;
	}
}

这里首先尝试获取方法上的 @Transactional 注解,如果存在的话则使用 parseTransactionAnnotation 方法解析参数,进到 parseTransactionAnnotation 方法中:

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());
	String timeoutString = attributes.getString("timeoutString");
	Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
			"Specify 'timeout' or 'timeoutString', not both");
	rbta.setTimeoutString(timeoutString);
	// 事务读写性
	rbta.setReadOnly(attributes.getBoolean("readOnly"));
	// 可选的限定描述符,指定使用的事务管理器
	rbta.setQualifier(attributes.getString("value"));
	rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));
	// 回滚的类型
	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;
}

分别解析出注解中的属性信息,并包装为 TransactionAttribute 类型对象。

下面再回到 getTransactionAttribute 方法中,通过 computeTransactionAttribute 方法获取到事务的属性信息后,如果结果不为空的话进行属性的补充后直接将属性信息返回给了 TransactionAttributeSourcePointcut 中的 matches 方法,这里如果结果不为空返回就是为 true ,也就是匹配符合条件了。

在这里插入图片描述

五、事务拦截器的触发过程

AOP 中查找完匹配的增强方法后,如果存在会创建一个代理对象放入 Spring 容器中,在代理对象执行时,先根据 Advisor 生成一个 Advice 类型的增强器链,这里以 JDK 动态代理为例,在 JdkDynamicAopProxy 类中 invoke 方法下触发的 this.advised.getInterceptorsAndDynamicInterceptionAdvice

在这里插入图片描述

其中从 Advisor 中获取 Advice 对象的逻辑在DefaultAdvisorAdapterRegistry类下的 getInterceptors 方法中:

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
	List<MethodInterceptor> interceptors = new ArrayList<>(3);
	Advice advice = advisor.getAdvice();
	if (advice instanceof MethodInterceptor) {
		interceptors.add((MethodInterceptor) advice);
	}
	for (AdvisorAdapter adapter : this.adapters) {
		if (adapter.supportsAdvice(advice)) {
			interceptors.add(adapter.getInterceptor(advisor));
		}
	}
	if (interceptors.isEmpty()) {
		throw new UnknownAdviceTypeException(advisor.getAdvice());
	}
	return interceptors.toArray(new MethodInterceptor[0]);
}

增强切面方法的执行主要在 ReflectiveMethodInvocation 类下的 proceed() 中:

public Object proceed() throws Throwable {
	// 该方法为 jdk的AOP实现的核心
	// 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;
		//获取被代理的对象类型
		Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
		//进行动态匹配
		if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
			return dm.interceptor.invoke(this);
		}
		//如果动态匹配失败,递归进行proceed
		//不匹配就不执行当前的拦截器
		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);
	}
}

这里会顺序执行 MethodInterceptor 类型的 invoke 方法 ,从前面的分析可以知道 BeanFactoryTransactionAttributeSourceAdvisor 中的 AdviceTransactionInterceptor,而 TransactionInterceptor 又实现了MethodInterceptor ,因此这里看到 TransactionInterceptor 类的 invoke 方法下:

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);
}

这里又调用了父类 TransactionAspectSupport 下的 invokeWithinTransaction 方法,下面主要看到该方法中:

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();
	// 获取前面解析出来 @Transactional 注解的属性
	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
	// 根据事物属性获取对应的事物管理器,一般为 DataSourceTransactionManager
	final TransactionManager tm = determineTransactionManager(txAttr);
	// 是否存在 反应式事务
	if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
		....省略...
	}

	PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
	// 获取目标方法唯一标识,如 com.xx.XX.xx
	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
	// 根据条件执行目标增强
	if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
		// Standard transaction demarcation with getTransaction and commit/rollback calls.
		// 判断是否有必要创建一个事物,根据事物传播行为决定,如果需要则新建事务信息,还会保存至 ThreadLocal 中
		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 (retVal != null && 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 {
	     ....省略...
	}
}

这里会获取到前面拿到前面解析出来 @Transactional 注解的属性,并获取到事物管理器,一般为 DataSourceTransactionManager ,后面我们也主要看该类型的事务操作过程。

其中里面几个重要的方法: createTransactionIfNecessary 方法主要开启事务,completeTransactionAfterThrowing 方法回滚事务,commitTransactionAfterReturning 方法提交事务。

五、开启事务的过程

看到 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 方法中,如果事务不存在就开启一个事务:

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();

	// 首次进入,connectionHolder为空,不存在事务
	// 如果事务已经存在
	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'");
	}
	// 如果事务隔离级别为 requered,requires_new,nested, 则加入事务
	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);
	}
}

这里首先通过 doGetTransaction 方法获取事务对象,前提有事务的话,本质就是去 ThreadLocal 中获取连接句柄,看到 DataSourceTransactionManager 类下 doGetTransaction 方法:

protected Object doGetTransaction() {
	DataSourceTransactionObject txObject = new DataSourceTransactionObject();
	txObject.setSavepointAllowed(isNestedTransactionAllowed());
	//当前数据源,在当前线程 的 连接对象
	ConnectionHolder conHolder =
			(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
	// 将该连接对象,设置进事务中
	txObject.setConnectionHolder(conHolder, false);
	return txObject;
}

其中 TransactionSynchronizationManager.getResource 就是去 ThreadLocal 中获取:

在这里插入图片描述
在这里插入图片描述

下面回到 getTransaction 方法中,如果不存在事务的话,下面通过 startTransaction 方法开启事务,看到该方法中:

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);
	// 开启事务,
	// jdbc: transaction -> DataSourceTransactionObject jta: JtaTransactionObject
	// jms: transaction-> JmsTransactionObject  jca: CciLocalTransactionObject
	doBegin(transaction, definition);
	// 开启事务后,改变事务状态
	prepareSynchronization(status, definition);
	return status;
}

再看到 doBegin 方法中,来到 DataSourceTransactionManager 类下的方法:

protected void doBegin(Object transaction, TransactionDefinition definition) {
	DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
	Connection con = null;

	try {
		// 如果之前没有连接,则新建连接
		if (!txObject.hasConnectionHolder() ||
				txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
			// 此处是 从连接池获取连接,算是应用层底层与上层的交界处
			Connection newCon = obtainDataSource().getConnection();
			if (logger.isDebugEnabled()) {
				logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
			}
			// 将首次创建的连接,保存至 connectionHolder,connectionHolder 由 ThreadLocal实现
			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());

		// 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).
		// 有事务的环境,如果设置了自动提交,则会自动切换到 手动提交
		if (con.getAutoCommit()) {
			txObject.setMustRestoreAutoCommit(true);
			if (logger.isDebugEnabled()) {
				logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
			}
			// 关闭连接得自动提交,这一步实际上就开启了事务
			con.setAutoCommit(false);
		}

		// 设置事务只读状态
		prepareTransactionalConnection(con, definition);
		txObject.getConnectionHolder().setTransactionActive(true);

		int timeout = determineTimeout(definition);
		if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
			txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
		}

		// Bind the connection holder to the thread.
		// 如果是新创建的事务
		if (txObject.isNewConnectionHolder()) {
			// 就 建立 当前线程,和 数据库连接的绑定关系
			TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
		}
	}

	catch (Throwable ex) {
		if (txObject.isNewConnectionHolder()) {
			DataSourceUtils.releaseConnection(con, obtainDataSource());
			txObject.setConnectionHolder(null, false);
		}
		throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
	}
}

获取到数据库连接后,通过 con.setAutoCommit(false) 将自动提交关闭,实际上就已经开启了事务。

在最后 TransactionSynchronizationManager.bindResource 就是将当前连接句柄存放发到前面提到的 resources ThreadLocal 中:

在这里插入图片描述

六、回滚事务过程

看到 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;
			}
		}
	}
}

如果设置了 rollbackOn 参数,会异常类型判断是否符合,不符合直接提交事务。

如果符合则获取到事务管理器进行 回滚操作,看到 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);
}

再看到 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 {
				...省略...
			}
		}
		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);
	}
}

主要回滚逻辑在 doRollback 方法中,看到DataSourceTransactionManager 类下的该方法:

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 translateException("JDBC rollback", ex);
	}
}

获取到数据库连接后,通过 con.rollback() 进行事务的回滚。

七、提交事务的过程

看到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());
	}
}

这里使用了事务管理器的 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);
}

再看到 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");
				}
				// 不提交,只是将 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);
	}
}

这里的判断逻辑和回滚的逻辑差不多,主要提交逻辑在 doCommit 方法中,看到 DataSourceTransactionManager 类下该方法:

protected void doCommit(DefaultTransactionStatus status) {
	DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
	Connection con = txObject.getConnectionHolder().getConnection();
	if (status.isDebug()) {
		logger.debug("Committing JDBC transaction on Connection [" + con + "]");
	}
	try {
		// 通过数据库连接,实现事务提交
		con.commit();
	}
	catch (SQLException ex) {
		throw translateException("JDBC commit", ex);
	}
}

获取到数据库连接后,通过 con.commit() 进行事务的提交。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/422253.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

BGP对等体建邻配置

BGP对等体大体分为EBGP对等体和IBGP对等体。而BGP对等体的建邻主要分为两种&#xff1a;1、使用物理接口建邻 2、使用环回借口建邻&#xff0c;针对不同的BGP对等体选用不同的建邻方式。 EBGP的建邻主要使用的是物理接口建邻 IBGP的建邻主要使用的是环回接口建邻 这两种建邻方…

VBA的面向接口编程

工作中有时候会用到VBA&#xff08;Visual Basic for Applications&#xff09;&#xff0c;不是很多&#xff0c;也没有专门去学习VBA&#xff0c;用的时候遇到问题就上网去查资料&#xff0c;解决问题了就放下了。 今天被同事问到VBA中类的用法&#xff0c;我从来没有用过&am…

论文解读:基于 OpenMLDB 的流式特征计算优化

近期&#xff0c;数据库领域的顶级学术会议 ICDE 2023 在迪斯尼主题公园的故乡 - 美国的安纳海姆&#xff08;Anaheim&#xff09;举办。由 OpenMLDB 开源社区和新加坡科技设计大学&#xff08;Singapore University of Technology and Design&#xff09;联合完成的研究工作在…

Vue2-黑马(三)

目录&#xff1a; &#xff08;1&#xff09;vue2-axios &#xff08;2&#xff09;axios-发送请求 &#xff08;3&#xff09;vue2-axios-请求体格式 &#xff08;4&#xff09;vue2-axios-默认配置 &#xff08;1&#xff09;vue2-axios 已经配置了代理&#xff0c;可以…

项目部署---shell脚本自动部署项目

通过shell脚本自动部署项目 操作步骤&#xff1a; 在Linux中安装Git在Linux中安装maven编写shell脚本&#xff08;拉取代码、编译、打包、启动&#xff09;为用户授予执行shell脚本的权限执行shell脚本 执行过程&#xff1a;Linux服务器&#xff08;编译、打包、启动&#x…

每天一道大厂SQL题【Day21】华泰证券真题实战(三)

每天一道大厂SQL题【Day21】华泰证券真题实战(三) 大家好&#xff0c;我是Maynor。相信大家和我一样&#xff0c;都有一个大厂梦&#xff0c;作为一名资深大数据选手&#xff0c;深知SQL重要性&#xff0c;接下来我准备用100天时间&#xff0c;基于大数据岗面试中的经典SQL题&…

爱智EdgerOS之深入解析爱智云原生产品ECSM

一、云原生简介 近些年来&#xff0c;云原生逐渐被业界认可和接受&#xff0c;在国内&#xff0c;包括政府、金融、通信、能源在内的众多领域的大型机构和企业都实现了不同程度的云化&#xff0c;那么什么是云原生呢&#xff1f;云原生计算基金会提供了官方的定义&#xff1a;…

参考|雨水情测报和大坝安全监测系统建设方案

解决方案 小型雨水情测报和大坝安全监测系统解决方案&#xff0c;系统主要由降雨量监测站、水库水位监测站、大坝安全监测中的渗流量、渗流压力和变形监测站及视频和图像监测站等站点组成&#xff0c;同时建立规范、统一的监测平台&#xff0c;集数据传输、信息共享、数据储存…

比较系统的学习 pandas (6)

pandas 数据类型转换 在开始数据分析前&#xff0c;有时需要为数据分配好合适的类型&#xff0c;这样才能 够高效地处理数据 # 对所有字段指定统一类型 data pd.DataFrame(data, dtypefloat32) # 对每个字段分别指定 data pd.read_excel(data.xlsx, dtype{name: string, sc…

CUDA和TensorRT入门

CUDA 官方教程&#xff1a;CUDA C Programming Guide (nvidia.com) 一、基础知识 首先看一下显卡、GPU、和CUDA的关系介绍&#xff1a; 显卡、GPU和CUDA简介_吴一奇的博客-CSDN博客 延迟&#xff1a;一条指令返回的时间间隔&#xff1b; 吞吐量&#xff1a;单位时间内处理…

libwebsockets交叉编译

libwebsockets官网&#xff1a;https://libwebsockets.org/ github&#xff1a;https://github.com/warmcat/libwebsockets 首先下载libwebsockets源码&#xff0c;源码既可以在其官网上下载&#xff0c;也可以到github上下载。这里以v4.1.6为例&#xff0c;https://github.co…

react项目中自定义一个markdown编辑器

Markdown 是一种轻量级标记语言。 Markdown是一种简单的格式化文本的方法&#xff0c;在任何设备上看起来都很棒。它不会做任何花哨的事情&#xff0c;比如改变字体大小、颜色或类型——只是基本的&#xff0c;使用你已经知道的键盘符号。 它还允许人们使用易读易写的纯文本格…

为什么众多大型国企都在升级企业数智化底座?

在数字经济大潮中&#xff0c;数字化转型已不是企业的“选修课”&#xff0c;而是关乎企业生存和长远发展的“必修课”。在企业数字化转型中&#xff0c;国有企业特别是中央企业普遍将数字化转型战略作为“十四五”时期业务规划的重要内容之一&#xff0c;数字化能力也成为衡量…

图文详解CAN Log文件 - ASC文件格式

目录 1 CAN Log文件 -- ASC文件格式 1.1 Header 1.2 版本编号 1.3 经典CAN网络中的描述 1.3.1 经典CAN Standard标准帧的描述 1.3.2 经典CAN Extended扩展帧的描述 1.3.3 CAN Remote远程帧的描述 1.3.4 CAN Error错误帧的描述 1.4 CANFD网络中的描述 1.4.1 经典CAN S…

图解并用 C 语言实现非比较排序(计数排序、桶排序和基数排序)

目录 一、计数排序 二、桶排序 三、基数排序 一、计数排序 算法步骤&#xff1a; 找出待排序数组 arr 中的最小值和最大值&#xff08;分别用 min 和 max 表示&#xff09;。 创建一个长度为 max - min 1、元素初始值全为 0 的计数器数组 count。 扫描一遍原始数组&…

Nacos客户端实例注册源码分析-篇一

Nacos客户端实例注册源码分析-篇一 版本 nacos 服务器端 nacos 2.0.3 实例客户端注册入口 注册案例 回到之前搭建的服务提供者项目 9002 &#xff0c;在真实的生产环境下&#xff0c;如果需要让某一个服务注册到 Nacos 的服务当中&#xff0c;我们引入对应的 nacos 发现依赖&…

4月Google Play政策更新,游戏上架需要注意这几点

3月21日&#xff0c;据路透社报道&#xff0c;由于发现国内某知名电商应用存在恶意软件问题&#xff0c;谷歌已暂时将该APP从商店下架&#xff0c;并表示&#xff1a;将该APP下架是一种安全预防措施&#xff0c;已经下载的用户也会收到警告&#xff0c;提示他们进行卸载。 4月…

基于深度学习的动物识别系统(YOLOv5清新界面版,Python代码)

摘要&#xff1a;动物识别系统用于识别和统计常见动物数量&#xff0c;通过深度学习技术检测日常几种动物图像识别&#xff0c;支持图片、视频和摄像头画面等形式。在介绍算法原理的同时&#xff0c;给出Python的实现代码、训练数据集以及PyQt的UI界面。动物识别系统主要用于常…

c/c++:算术运算符,赋值运算,逻辑运算,比较运算,三目运算,逗号运算,数据类型转换

c/c&#xff1a;算术运算符&#xff0c;赋值运算&#xff0c;逻辑运算&#xff0c;比较运算&#xff0c;三目运算&#xff0c;逗号运算&#xff0c;数据类型转换 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;此时学会c的…

【自定义表格穿梭框】自定义封装jqgrid表格穿梭框,支持分页复选全选(附完整源码及效果图)

【写在前面】其实之前业务中也有这个方面的需求&#xff0c;但是总觉得自己写的有点乱&#xff0c;此时也就借这个机会重新封装一个公共的函数去实现这个穿梭框的效果&#xff0c;支持分页勾选&#xff0c;页面展示已选中和未选择的数据&#xff0c;使得系统操作更友好。 涉及知…