想了解事务源码的小伙伴肯定熟悉 Spring
中事务的使用,先来回顾一下。
导入
spring-tx
包;配置类加上
@EnableTransactionManagement
注解;需要事务控制的方法上加上
@Transactional
注解。
一个最基本的事务控制就完成了。
对于
SpringBoot
项目,不需要加上@EnableTransactionManagement
注解,因为有SpringBoot
自动装配。在spring-boot-autoconfigure
包下spring.factories
文件中,EnableAutoConfiguration
有一个SPI
实现TransactionAutoConfiguration
,里面包含了@EnableTransactionManagement
注解。所以,原理是一样的,只是配置方式不同。
1. @EnableTransactionManagement 注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default 2147483647;
}
还是老套路,@EnableXXX
+ @Import
注解组合,来看一下 TransactionManagementConfigurationSelector
。
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
public TransactionManagementConfigurationSelector() {
}
protected String[] selectImports(AdviceMode adviceMode) {
switch(adviceMode) {
case PROXY:
return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[]{this.determineTransactionAspectClass()};
default:
return null;
}
}
}
@EnableTransactionManagement
注解默认使用 PROXY
模式来增强事务,所以 selectImports
方法返回两个类的全限定类名:AutoProxyRegistrar
、ProxyTransactionManagementConfiguration
,事务最终起作用的是上述两个类的功能。
2. AutoProxyRegistrar
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
......
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
......
}
}
实现了 ImportBeanDefinitionRegistrar
接口,手动向 IOC
容器中导入组件。如果 @EnableTransactionManagement
注解中设置 adviceMode
为 PROXY
(默认PROXY
),则会利用 AopUtils
创建组件,并且如果 @EnableTransactionManagement
设置 proxyTargetClass
为true,则还会额外导入组件(默认为false)。
2.1 AopConfigUtils.registerAutoProxyCreatorIfNecessary
// AopConfigUtils
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
可以看到最终是往 BeanDefinitionRegistry
注册了一个类为 InfrastructureAdvisorAutoProxyCreator
的 beanDefinition
,名字为静态变量 AUTO_PROXY_CREATOR_BEAN_NAME
的值 :org.springframework.aop.config.internalAutoProxyCreator
。看到这个名字是不是很熟悉?AOP
那块有讲过,不记得的或者没看过的小伙伴可以去看一下哦。
AOP
中名字为 AUTO_PROXY_CREATOR_BEAN_NAME
的 beanDefinition
对应的类是 AnnotationAwareAspectJAutoProxyCreator
,那和事务的这个不是冲突了吗?别急,仔细看下,注册到 BeanDefinitionRegistry
之前还有个判断 !cls.getName().equals(apcDefinition.getBeanClassName())
,判断要注册的 beanDefinition
所属类名和已存在的是否一致,即 AnnotationAwareAspectJAutoProxyCreator
和 InfrastructureAdvisorAutoProxyCreator
的判断,而这个是根据优先级判断的,那个优先级高就用哪个。而优先级的判断是根据数组里面的下标。
// AopConfigUtils
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
static {
// Set up the escalation list...
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
private static int findPriorityForClass(@Nullable String className) {
for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
Class<?> clazz = APC_PRIORITY_LIST.get(i);
if (clazz.getName().equals(className)) {
return i;
}
}
throw new IllegalArgumentException(
"Class name [" + className + "] is not a known auto-proxy creator class");
}
AnnotationAwareAspectJAutoProxyCreator
在数组最后,所以优先级比 InfrastructureAdvisorAutoProxyCreator
高。
因此,在同时引入了 Spring AOP
和Spring TX
的情况下,最终生效的是AnnotationAwareAspectJAutoProxyCreator
,即使 AnnotationAwareAspectJAutoProxyCreator
先被注册 ,最终都会被覆盖 。点开源码比较,AnnotationAwareAspectJAutoProxyCreator
多了 AspectJ
相关的逻辑。
2.2 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry)
设置事务增强的类全部使用 Cglib
代理类的方式,对应 AOP
中 AbstractAutoProxyCreator # createProxy
方法中的 proxyFactory.isProxyTargetClass()
。
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
3. ProxyTransactionManagementConfiguration
这个配置类有三个组件。
3.1 TransactionAttributeSource
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
仅仅创建了一个 AnnotationTransactionAttributeSource
。
3.1.1 TransactionAttributeSource
先看一下接口。
public interface TransactionAttributeSource {
default boolean isCandidateClass(Class<?> targetClass) {
return true;
}
@Nullable
TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass);
}
主要是下面的 getTransactionAttribute
方法,方法参数是一个 方法 + 类。实际上就是根据一个类 + 方法,解析转换为 TransactionAttribute
。而 TransactionAttribute
继承自 TransactionDefinition
,所以可以这样理解:TransactionAttribute
可以根据一个具体的类中的方法,解析转换为一个 TransactionDefinition
( TransactionAttribute
)。
3.1.2 AnnotationTransactionAttributeSource
直接定位类注释中关键的一句:
This class reads Spring's JDK 1.5+ @Transactional annotation and exposes corresponding transaction attributes to Spring's transaction infrastructure.
由此可见 AnnotationTransactionAttributeSource
是读取和解析标注有 @Transactional
注解的方法的。怎么解析的放到下面讲。
3.2 TransactionInterceptor 事务拦截器
@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;
}
TransactionInterceptor
实现了 MethodInterceptor
,AOP
部分讲过MethodInterceptor
接口是 AOP 增强的核心拦截器接口,利用 AOP 生成的代理对象中都会包含一组 MethodInterceptor
接口的实现类对象。并且它这里还依赖了上面说到的 TransactionAttributeSource
。
3.3 BeanFactoryTransactionAttributeSourceAdvisor 事务增强器
@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);
// 取@EnableTransactionManagement的order属性
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
使用 BeanFactoryTransactionAttributeSourceAdvisor
作为事务增强器的实现,并给它配置了 TransactionAttributeSource
。作为一个增强器,肯定得有 Advice
和 PointCut
,但是看代码只设置了 Advice
(即 transactionInterceptor
),PointCut
呢?我们进入 BeanFactoryTransactionAttributeSourceAdvisor
这个类里面:
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private TransactionAttributeSource transactionAttributeSource;
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
......
}
哦,原来切入点在类内部就已经初始化好了,类型是 TransactionAttributeSourcePointcut
,而且实现了 getTransactionAttributeSource
方法,返回的正好是配置类中的 transactionAttributeSource
,这个方法有什么用呢?直接看 TransactionAttributeSourcePointcut
的核心 matches
方法:
// TransactionAttributeSourcePointcut
public boolean matches(Method method, Class<?> targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
就是拿 TransactionAttributeSource
去根据方法和方法所属类,判断是否有对应的事务定义信息(是否被 @Transactional
注解标注)。
4. 代理类生成
事务代理类的生成和 AOP
代理类的生成是一样的,所以直接定位到核心处理点,前面的逻辑就不再赘述了。回到老地方:
// AbstractAdvisorAutoProxyCreator
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
advisorRetrievalHelper.findAdvisorBeans()
在 AOP
那块讲过,就是找出实现了 Advisor
接口的 bean
,而前面说到的 BeanFactoryTransactionAttributeSourceAdvisor
正好匹配。可以随便写个测试类,方法加上 @Transactional
注解,并注入到 IOC
,将断点打到这,查看结果。
Advisor
找到之后,就是判断是否能匹配了。这块的判断和 AOP
有点区别。
匹配调用的是 methodMatcher.matches
,而 AOP
中匹配是上面那一个(251行)。
methodMatcher.matches
方法就是前面说过的 TransactionAttributeSourcePointcut
中的 matches
方法,只不过先前只是简单看了一下,下面来深入解析一下:
// TransactionAttributeSourcePointcut
public boolean matches(Method method, Class<?> targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
// AbstractFallbackTransactionAttributeSource(AnnotationTransactionAttributeSource 的父类)
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
.....
// First, see if we have a cached value.
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
.......
}
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
方法生成 TransactionAttribute
。
// AbstractFallbackTransactionAttributeSource
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// 非 public 方法返回 null
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
.........
}
// AnnotationTransactionAttributeSource
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
最终使用 TransactionAnnotationParser
解析方法并转换,而 TransactionAnnotationParser
有三个实现类,那肯定不用说就是 SpringTransactionAnnotationParser
了。
// SpringTransactionAnnotationParser
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
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());
......
}
就是找对应的方法上面 @Transactional
注解相关属性如 propagation
传播行为,·封装到 AnnotationAttributes
里面,最终根据 AnnotationAttributes
获取 TransactionAttribute
并返回,注意类型是 RuleBasedTransactionAttribute
,继承自 DefaultTransactionAttribute
。
TransactionAttribute
不为空,那最初的 matches
方法就返回 true
,说明增强器 BeanFactoryTransactionAttributeSourceAdvisor
可以匹配该方法(即方法上面有 @Transactional
注解)。
增强器拿到了,接下来就是 createProxy
了,这里不再重复解析了。
5. 代理类执行
由于 AOP
部分已经讲过代理类的执行逻辑,所以这里我们直接定位到 TransactionInterceptor
的 invoke
方法。
// TransactionInterceptor
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
@Override
public Object getTarget() {
return invocation.getThis();
}
@Override
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
进入 invokeWithinTransaction
方法,在父类 TransactionAspectSupport
中。这个方法篇幅较长,所以下面拆开来讲。
5.1 获取方法对应的事务定义
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final TransactionManager tm = determineTransactionManager(txAttr);
.......
前面两行代码在 代理类生成章节已经分析过了,这里可以直接从缓存中获取 TransactionAttribute
。
5.2 决定事务管理器
protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
// Do not attempt to lookup tx manager if no tx attributes are set
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
}
else {
TransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}
代码里获取事务管理的方式有很多种,但实际 Debug
的时候走的是最后一个方式,即通过 beanFactory
获取。
对于 Spring
项目,需要在配置类中手动注入到 IOC
容器。
@Configuration
public class TransactionConfiguration {
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("...");
dataSource.setUsername("...");
dataSource.setPassword("....");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
@Bean
public TransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
对于 SpringBoot
项目,引入了相关持久层框架(MyBatis
等),则会自动注入。
5.3 响应式事务的处理
// ......
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
throw new TransactionUsageException(
"Unsupported annotated transaction on suspending function detected: " + method +
". Use TransactionalOperator.transactional extensions instead.");
}
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
if (adapter == null) {
throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
method.getReturnType());
}
return new ReactiveTransactionSupport(adapter);
});
return txSupport.invokeWithinTransaction(
method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
}
// ......
这里不研究响应式事务,响应式事务用的也不多,感兴趣的可以自行研究。
5.4 事务控制
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// 开启事务
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// 执行原方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 回滚事务
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;
}
仔细一看,其实就是类似 AOP
的环绕通知。
5.4.1 创建事务
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);
}
先将原来的 TransactionAttribute
包装为 DelegatingTransactionAttribute
。而 tm.getTransaction(txAttr)
这行则是真正开启事务。和原生 JDBC
开启事务一样,tm.getTransaction(txAttr)
最终会在 DataSourceTransactionManager
的 doBegin
方法设置自动提交为 false
。
protected void doBegin(Object transaction, TransactionDefinition definition) {
.......
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
.......
}
将断点打在创建事务的下一行,查看返回的 TransactionInfo
包含哪些内容。
可以看到,事务定义信息和状态都封装好了,状态中 completed
值为 false
。
5.4.2 事务提交
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());
}
}
txInfo.getTransactionManager().commit
提交事务。commit
方法的实现则是在 AbstractPlatformTransactionManager
这个类中。
// AbstractPlatformTransactionManager
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);
}
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
// ......
if (status.hasSavepoint()) {
// 如果当前事务存在保存点,则处理保存点的逻辑
}
// 对于新事务,直接提交事务即可
else if (status.isNewTransaction()) {
// logger ......
unexpectedRollback = status.isGlobalRollbackOnly();
doCommit(status);
}
// ......
}
核心是 doCommit
方法,在 DataSourceTransactionManager
中。
// 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);
}
}
这里就是熟悉的原生 jdbc
操作了,获取 Connection
,然后执行 commit
方法。
5.4.3 事务回滚
@Transactional
public void test() {
throw new RuntimeException("模拟异常");
}
手动模拟异常,异常会被捕获,进入到下面的 completeTransactionAfterThrowing
方法。
注意这个方法中的 Throwable
参数,这个就业务方法执行过程中抛出的异常。
// TransactionAspectSupport
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
// logger .....
// 如果当前异常在回滚范围内,则回滚事务
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
} // catch .....
}
else {
// 否则依然提交事务
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}// catch .....
}
}
}
那回滚范围怎么理解呢?我们看 transactionAttribute # rollbackOn
方法,前面分析过 transactionAttribute
被包装成 DelegatingTransactionAttribute
。
// DelegatingTransactionAttribute
private final TransactionAttribute targetAttribute;
public DelegatingTransactionAttribute(TransactionAttribute targetAttribute) {
super(targetAttribute);
this.targetAttribute = targetAttribute;
}
public boolean rollbackOn(Throwable ex) {
return this.targetAttribute.rollbackOn(ex);
}
DelegatingTransactionAttribute
中 targetAttribute
对应的类型就是 txAttr
原本的类型 RuleBasedTransactionAttribute
,我们直接到这个类看对应的方法。
// RuleBasedTransactionAttribute
public boolean rollbackOn(Throwable 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;
}
}
}
// User superclass behavior (rollback on unchecked) if no rule matches.
if (winner == null) {
// 调用父类 DefaultTransactionAttribute 的方法
return super.rollbackOn(ex);
}
return !(winner instanceof NoRollbackRuleAttribute);
}
中间有一个回滚规则的判断,对于例子中的使用,rollbackRules
为 null
,所以 winner
也为 ·null
,最终是调用父类 DefaultTransactionAttribute
的 rollbackOn
方法,看一下父类的回滚规则判断:
// DefaultTransactionAttribute
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
哦,原来是判断业务抛出的异常类型啊。只有异常是 RuntimeException
或 Error
这两种类型的异常才能正常执行回滚逻辑,其他异常则依旧正常提交。
对于异常这里补充一下:
Java
中的异常主要分两大类:
Exception
:程序本身可以处理的异常,可以通过catch
捕获。Exception
又可以分为Checked Exception
(受检查异常,必须处理) 和Unchecked Exception
(不受检查异常,可以不 处理)。常见的受检查异常有:IO
相关的异常、ClassNotFoundException
。不受检查异常有:空指针异常、数组越界异常等。RuntimeException
及其子类都是不受检查异常,其他则都是受检查异常。
Error
:程序本身无法处理的错误。如内存溢出(OutOfMemoryError
)等。
所以,通俗来讲:业务逻辑出现的空指针等不受检查异常或 Error
,会被回滚。而文件读写等,Spring
无法回滚,即使出现异常,也会正常提交。
那如果想对于所有的 Exception
,都能执行回滚,要怎么做呢? @Transactional
有一个 rollbackFor
的属性,可以指定回滚异常的类型。所以只需这样写 :@Transactional(rollbackFor = Exception.class)
。前面说过 RuleBasedTransactionAttribute
有回滚规则的判断,如果当前事务定义信息没有回滚规则的话就走默认的回滚判断,所以加了之后一定有回滚规则的,不然就回滚不了了,将断点打在回滚规则是否为 null
的地方查看结果。
果然如此,有一个回滚规则,且回滚对应的异常为 Exception
。且 rollbackRules
是一个 List
类型,说明可以有多个回滚规则,而 @Transactional
的 rollbackFor
属性的类型也是 Class
数组,可以指定多种异常类型,正好对应。
if
里面的逻辑就是判断业务抛出的异常类型是否为指定异常,RuntimeException
是 Exception
的子类,depth
就是对应异常树中的位置。如:指定 Exception
为顶级异常,depth
为0;RuntimeException
在 Exception
的下一级,深度加1,对应的 depth
就是 1;RuntimeException
的直接子类对应的 depth
就是2。以此类推。
简单来说:就是判断业务抛出的异常类型是否为指定异常,是则返回 true
,匹配成功;否则依旧执行默认的回滚判断。
那 rollbackRules
是什么时候初始化的?回到构造 RuleBasedTransactionAttribute
的地方。
// SpringTransactionAnnotationParser
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
........
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;
}
取出了 @Transactional
中与回滚相关的属性值,封装为 RollbackRuleAttribute
,供后续回滚异常的判断。
判断完成后,就是执行回滚逻辑了,最终还是是原生 jdbc 的事务操作,拿到 Connection
,执行 rollback
方法回滚事务。这里就不再展开讲了。
评论区