回答
在 Spring 中,事务的传播机制并不会在多线程环境下生效。这是因为 Spring 事务的实现是基于 ThreadLocal
。一个事务上下文与单个线程绑定。所以,如果我们在一个方法里面开启一个新的线程来执行任务,这个新线程是无法继承原有事务上下文的,会导致事务隔离。
举个简单的例子,在一个主线程中开启了事务,而在这个事务过程中启动了一个新的线程,这个新线程的操作并不会受到主线程事务的控制。即使主线程事务回滚,子线程的事务依然会提交。
详解
以 @Transaction
为例。
我们知道 @Transaction
的底层是基于 AOP 的,而 TransactionInterceptor
则负责拦截代理对象目标方法,在前后增加事务控制的逻辑,事务方法的执行最终都会由TransactionInterceptor
的invoke()
拦截增强:
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 委托给 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();
}
});
}
委托给父类 TransactionAspectSupport 的 invokeWithinTransaction()
处理:
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);
// 1--获取事务管理器
final TransactionManager tm = determineTransactionManager(txAttr);
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
// 省略部分代码...
}
// 2---获取 PlatformTransactionManager,PlatformTransactionManager 是Spring 中事务管理的核心接口,它负责管理事务的创建、提交和回滚等操作
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// 3-- 创建TransactionInfo
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// 4--调用业务方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 5--发生异常,回滚事务、提交事务?
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 6--清除事务
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);
}
}
// 7-- 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// 省略很多代码
return result;
}
}