Spring 事务全链路解析(三):TransactionInterceptor 如何开启一个事务
约 4434 字大约 15 分钟
2026-05-24
在上一篇文章中,我们揭示了@Transactional注解是如何被Spring激活,以及如何为Bean创建事务代理的。但代理对象创建完成后,当方法被调用时,事务是如何开启的呢?
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void createUser(User user) {
userRepository.save(user);
}
}
// 调用时
userService.createUser(user); // 事务在这里是如何开启的?本文将深入TransactionInterceptor的核心方法,完整追踪事务开启的全过程。
一、方法调用的拦截入口
1.1 代理对象的方法调用
当我们调用userService.createUser(user)时,实际执行的是代理对象的方法。根据代理类型不同:
JDK动态代理:
// 生成的代理类大致如下
public class UserServiceProxy implements UserService {
private UserService target;
private MethodInterceptor transactionInterceptor;
public void createUser(User user) {
MethodInvocation invocation = new ReflectiveMethodInvocation(
target, "createUser", new Object[]{user});
return transactionInterceptor.invoke(invocation);
}
}CGLIB代理:
// CGLIB生成的子类大致如下
public class UserService$$EnhancerBySpringCGLIB extends UserService {
private MethodInterceptor transactionInterceptor;
public void createUser(User user) {
MethodProxy methodProxy = ...;
return transactionInterceptor.intercept(this, methodProxy, new Object[]{user});
}
}无论哪种代理方式,最终都会调用到TransactionInterceptor.invoke()方法。
1.2 TransactionInterceptor.invoke方法
源码位置:spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionInterceptor.java
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
// 1. 获取目标类(实际被代理的类)
Class<?> targetClass = (invocation.getThis() != null
? AopUtils.getTargetClass(invocation.getThis()) : null);
// 2. 调用父类的事务处理方法
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();
}
}
);
}关键点:
invocation.getMethod():获取当前被调用的方法对象targetClass:获取目标类,可能是实现类而非接口invocation.proceed():这是一个回调,会在事务开启后被调用,执行目标方法- 核心逻辑全部委托给父类
TransactionAspectSupport.invokeWithinTransaction()
二、invokeWithinTransaction:事务管理的核心方法
这是整个Spring事务管理的核心方法,理解了它就理解了Spring事务的本质。
源码位置:spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
// ========== 第一步:获取事务属性 ==========
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null
? tas.getTransactionAttribute(method, targetClass) : null);
// ========== 第二步:确定事务管理器 ==========
final TransactionManager tm = determineTransactionManager(txAttr);
// 处理响应式事务(略过,我们关注传统事务)
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
// ... 响应式事务处理
}
// 转换为平台事务管理器
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
// ========== 第三步:生成事务标识(用于日志和监控) ==========
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
// ========== 第四步:处理事务 ==========
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// 标准事务管理流程(我们关注这个分支)
// 4.1 创建事务(如果需要)
TransactionInfo txInfo = createTransactionIfNecessary(
ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// 4.2 执行目标方法(调用下一个拦截器或目标方法)
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 4.3 发生异常时处理事务
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 4.4 清理事务信息
cleanupTransactionInfo(txInfo);
}
// 处理Vavr Try类型(略过)
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
// 4.5 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// CallbackPreferring方式(略过)
}
}核心流程:
- 获取事务属性:解析
@Transactional注解 - 确定事务管理器:找到合适的事务管理器
- 创建事务:调用
createTransactionIfNecessary - 执行目标方法:
invocation.proceedWithInvocation() - 异常处理:发生异常时回滚
- 提交事务:正常完成时提交
让我们逐一深入每个步骤。
三、第一步:获取事务属性
3.1 TransactionAttributeSource的作用
在上一篇文章中,我们知道AnnotationTransactionAttributeSource负责解析@Transactional注解。现在看看它是如何工作的。
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null
? tas.getTransactionAttribute(method, targetClass) : null);源码位置:spring-tx/src/main/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSource.java
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method,
@Nullable Class<?> targetClass) {
// 1. 检查是否是Object类的方法(如toString, hashCode等)
if (method.getDeclaringClass() == Object.class) {
return null;
}
// 2. 先检查缓存
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
return (cached == NULL_TRANSACTION_ATTRIBUTE ? null : cached);
}
else {
// 3. 解析事务属性
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// 4. 放入缓存
this.attributeCache.put(cacheKey,
(txAttr != null ? txAttr : NULL_TRANSACTION_ATTRIBUTE));
return txAttr;
}
}3.2 事务属性的解析过程
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method,
@Nullable Class<?> targetClass) {
// 1. 检查是否允许公共方法
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// 2. 获取具体方法(处理接口和实现类的情况)
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// 3. 先查找方法上的注解
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// 4. 查找类上的注解
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
// 5. 如果方法定义在不同接口上,检查接口方法
if (specificMethod != method) {
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}解析优先级:
- 实现类方法上的
@Transactional - 实现类类上的
@Transactional - 接口方法上的
@Transactional - 接口类上的
@Transactional
3.3 TransactionAttribute的内容
TransactionAttribute包含了@Transactional注解的所有配置:
public interface TransactionAttribute extends TransactionDefinition {
String getQualifier(); // 事务管理器限定符
boolean rollbackOn(Throwable ex); // 是否回滚
// 继承自TransactionDefinition:
int getPropagationBehavior(); // 传播行为
int getIsolationLevel(); // 隔离级别
int getTimeout(); // 超时时间
boolean isReadOnly(); // 是否只读
String getName(); // 事务名称
}例如,对于@Transactional(propagation = Propagation.REQUIRED, timeout = 30):
propagationBehavior = 0(REQUIRED)timeout = 30isolationLevel = -1(DEFAULT)readOnly = false
四、第二步:确定事务管理器
4.1 determineTransactionManager方法
final TransactionManager tm = determineTransactionManager(txAttr);源码位置:spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java
@Nullable
protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
// 如果没有事务属性或者没有BeanFactory,直接返回默认事务管理器
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
// 1. 检查@Transactional注解中是否指定了value/qualifier
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}
// 2. 检查@EnableTransactionManagement中是否指定了transactionManagerBeanName
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
}
// 3. 使用默认事务管理器
else {
TransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
// 从缓存中获取
defaultTransactionManager = this.transactionManagerCache.get(
DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
// 从BeanFactory中按类型获取
defaultTransactionManager = this.beanFactory.getBean(
TransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}查找策略:
@Transactional("customTxManager")→ 使用指定的事务管理器@EnableTransactionManagement配置 → 使用配置的事务管理器- 默认 → 从Spring容器中查找
PlatformTransactionManager类型的Bean
实际应用:
// 多数据源场景
@Qualifier("primaryTxManager")
@Autowired
private PlatformTransactionManager primaryTxManager;
@Qualifier("secondaryTxManager")
@Autowired
private PlatformTransactionManager secondaryTxManager;
@Transactional("primaryTxManager") // 使用主数据源事务
public void method1() { }
@Transactional("secondaryTxManager") // 使用副数据源事务
public void method2() { }五、第三步:创建事务(核心!)
这是本文的重点,也是整个事务管理的核心。
5.1 createTransactionIfNecessary方法
TransactionInfo txInfo = createTransactionIfNecessary(
ptm, txAttr, joinpointIdentification);源码位置:spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java
@SuppressWarnings("serial")
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// 1. 如果没有指定事务名称,使用方法标识作为事务名称
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");
}
}
}
// 2. 准备事务信息
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}关键点:
tm.getTransaction(txAttr):这是开启事务的真正入口!- 这里调用的是
PlatformTransactionManager接口的getTransaction方法 - 实际执行的是
AbstractPlatformTransactionManager.getTransaction()(模板方法模式)
5.2 PlatformTransactionManager接口
public interface PlatformTransactionManager extends TransactionManager {
/**
* 获取事务(开启或加入现有事务)
*/
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
/**
* 提交事务
*/
void commit(TransactionStatus status) throws TransactionException;
/**
* 回滚事务
*/
void rollback(TransactionStatus status) throws TransactionException;
}常用实现类:
DataSourceTransactionManager:JDBC事务JpaTransactionManager:JPA事务JtaTransactionManager:分布式事务HibernateTransactionManager:Hibernate事务
我们以DataSourceTransactionManager为例,它是使用最广泛的事务管理器。
六、AbstractPlatformTransactionManager.getTransaction
6.1 模板方法模式的典范
DataSourceTransactionManager继承自AbstractPlatformTransactionManager,后者实现了标准的模板方法模式。
源码位置:spring-tx/src/main/java/org/springframework/transaction/support/AbstractPlatformTransactionManager.java
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// 1. 使用默认配置(如果没有提供)
TransactionDefinition def = (definition != null
? definition : TransactionDefinition.withDefaults());
// 2. 获取事务对象(由子类实现)
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
// 3. 检查是否存在现有事务
if (isExistingTransaction(transaction)) {
// 存在现有事务 → 根据传播行为处理
return handleExistingTransaction(def, transaction, debugEnabled);
}
// 4. 检查超时设置
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// 5. 不存在现有事务 → 根据传播行为处理
// PROPAGATION_MANDATORY:必须有事务,否则抛异常
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
// PROPAGATION_REQUIRED / 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 {
// PROPAGATION_SUPPORTS / NOT_SUPPORTED / NEVER
// 创建"空"事务:没有实际事务,但可能有同步
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():获取当前事务对象(由子类实现)
- isExistingTransaction():检查是否存在现有事务
- 存在事务:调用
handleExistingTransaction()处理传播行为 - 不存在事务:根据传播行为决定是否创建新事务
- startTransaction():开启新事务
6.2 传播行为的处理策略
Spring支持7种传播行为:
| 传播行为 | 含义 | 有现有事务 | 无现有事务 |
|---|---|---|---|
| REQUIRED(默认) | 需要事务 | 加入现有事务 | 创建新事务 |
| SUPPORTS | 支持事务 | 加入现有事务 | 非事务执行 |
| MANDATORY | 强制事务 | 加入现有事务 | 抛异常 |
| REQUIRES_NEW | 新事务 | 挂起现有事务,创建新事务 | 创建新事务 |
| NOT_SUPPORTED | 不支持事务 | 挂起现有事务,非事务执行 | 非事务执行 |
| NEVER | 从不事务 | 抛异常 | 非事务执行 |
| NESTED | 嵌套事务 | 创建嵌套事务(savepoint) | 创建新事务 |
源码示例:handleExistingTransaction:
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition,
Object transaction,
boolean debugEnabled) throws TransactionException {
// PROPAGATION_NEVER:不允许有事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
// PROPAGATION_NOT_SUPPORTED:挂起现有事务,非事务执行
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
Object suspendedResources = suspend(transaction);
try {
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(transaction, suspendedResources);
throw ex;
}
}
// PROPAGATION_REQUIRES_NEW:挂起现有事务,创建新事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(transaction, suspendedResources);
throw ex;
}
}
// PROPAGATION_NESTED:创建嵌套事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions");
}
// 创建savepoint
DefaultTransactionStatus status = prepareTransactionStatus(
definition, transaction, false, newSynchronization, debugEnabled, null);
status.createAndHoldSavepoint();
return status;
}
// PROPAGATION_REQUIRED / SUPPORTS / MANDATORY:加入现有事务
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}七、DataSourceTransactionManager的具体实现
现在让我们看看DataSourceTransactionManager是如何实现这些模板方法的。
源码位置:spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceTransactionManager.java
7.1 doGetTransaction:获取当前事务对象
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// 从TransactionSynchronizationManager中获取ConnectionHolder
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}关键点:
- 创建
DataSourceTransactionObject对象 - 从
TransactionSynchronizationManager获取当前线程绑定的ConnectionHolder - 如果当前线程已经有连接,说明已经存在事务
7.2 isExistingTransaction:检查是否存在事务
@Override
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
return (txObject.hasConnectionHolder()
&& txObject.getConnectionHolder().isTransactionActive());
}判断标准:
- 有
ConnectionHolder - 且连接的事务状态为活跃
7.3 doBegin:开启事务
这是最核心的方法,真正的数据库事务在这里开启!
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// 1. 检查是否有连接,如果没有则从数据源获取
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// ========== 从数据源获取物理连接 ==========
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
// 2. 标记连接与事务同步
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// 3. 设置隔离级别和只读模式
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(
con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
txObject.setReadOnly(definition.isReadOnly());
// 4. 关闭自动提交(关键!)
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false); // ← 这里!关闭自动提交,开启手动事务
}
// 5. 如果是只读事务,执行SET TRANSACTION READ ONLY
prepareTransactionalConnection(con, definition);
// 6. 标记事务为活跃状态
txObject.getConnectionHolder().setTransactionActive(true);
// 7. 设置超时时间
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// 8. 将ConnectionHolder绑定到当前线程
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);
}
}关键步骤:
- 获取物理连接:
dataSource.getConnection() - 关闭自动提交:
con.setAutoCommit(false)← 这是开启事务的关键! - 设置事务属性:隔离级别、只读模式、超时时间
- 绑定到线程:将
ConnectionHolder绑定到TransactionSynchronizationManager
7.4 连接获取的完整流程
// DataSourceTransactionManager.doBegin
Connection newCon = obtainDataSource().getConnection();这里的obtainDataSource()返回的是什么?
场景1:使用原生Druid数据源
@Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setUrl("jdbc:mysql://localhost:3306/test");
ds.setUsername("root");
ds.setPassword("password");
return ds;
}
// getConnection()实际调用
Connection conn = druidDataSource.getConnection();
// → 从Druid连接池获取连接场景2:使用Spring Boot自动配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.DriverSpring Boot会自动创建HikariDataSource或DruidDataSource(如果引入了druid-spring-boot-starter)。
八、事务信息的准备与绑定
8.1 prepareTransactionInfo方法
回到createTransactionIfNecessary方法:
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, String joinpointIdentification,
@Nullable TransactionStatus status) {
// 1. 创建TransactionInfo对象
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
if (logger.isTraceEnabled()) {
logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
// 2. 设置事务状态
txInfo.newTransactionStatus(status);
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No need to create transaction for [" + joinpointIdentification +
"]: This method is not transactional.");
}
}
// 3. 将TransactionInfo绑定到ThreadLocal
txInfo.bindToThread();
return txInfo;
}8.2 TransactionInfo的ThreadLocal绑定
private void bindToThread() {
// 保存旧的TransactionInfo(支持嵌套事务)
this.oldTransactionInfo = transactionInfoHolder.get();
// 设置新的TransactionInfo
transactionInfoHolder.set(this);
}TransactionInfo结构:
protected static final class TransactionInfo {
@Nullable
private final PlatformTransactionManager transactionManager; // 事务管理器
@Nullable
private final TransactionAttribute transactionAttribute; // 事务属性
private final String joinpointIdentification; // 事务名称
@Nullable
private TransactionStatus transactionStatus; // 事务状态
@Nullable
private TransactionInfo oldTransactionInfo; // 旧的事务信息(嵌套事务)
}ThreadLocal设计:
private static final ThreadLocal<TransactionInfo> transactionInfoHolder =
new NamedThreadLocal<>("Current aspect-driven transaction");这确保了:
- 每个线程有独立的事务上下文
- 支持嵌套事务(通过
oldTransactionInfo形成栈结构) - 线程安全
九、完整的执行流程图
┌─────────────────────────────────────────────────────────┐
│ 调用: userService.createUser(user) │
└────────────────────┬────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────┐
│ [代理对象] JDK Proxy / CGLIB │
│ 拦截方法调用 │
└────────────────────┬────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────┐
│ TransactionInterceptor.invoke() │
│ │
│ 1. 获取目标类 │
│ 2. 调用 invokeWithinTransaction() │
└────────────────────┬────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────┐
│ TransactionAspectSupport.invokeWithinTransaction() │
│ │
│ 1. 获取TransactionAttribute │
│ - 解析@Transactional注解 │
│ - 提取传播行为、隔离级别等 │
│ │
│ 2. 确定TransactionManager │
│ - 查找PlatformTransactionManager Bean │
│ │
│ 3. createTransactionIfNecessary() │
└────────────────────┬────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────┐
│ AbstractPlatformTransactionManager.getTransaction() │
│ │
│ 1. doGetTransaction() │
│ - 创建DataSourceTransactionObject │
│ - 从ThreadLocal获取ConnectionHolder │
│ │
│ 2. isExistingTransaction() │
│ - 判断是否存在现有事务 │
│ │
│ 3. 根据传播行为处理 │
│ - REQUIRED: 无事务 → 创建新事务 │
│ - REQUIRES_NEW: 挂起旧事务,创建新事务 │
│ - 等等... │
└────────────────────┬────────────────────────────────────┘
│ 创建新事务
↓
┌─────────────────────────────────────────────────────────┐
│ DataSourceTransactionManager.doBegin() │
│ │
│ 1. dataSource.getConnection() ← 从连接池获取连接 │
│ - Druid/HikariCP连接池 │
│ - 或原生JDBC连接 │
│ │
│ 2. con.setAutoCommit(false) ← 关闭自动提交! │
│ 【这就是开启事务的本质】 │
│ │
│ 3. 设置隔离级别、只读模式、超时时间 │
│ │
│ 4. TransactionSynchronizationManager.bindResource() │
│ - 将ConnectionHolder绑定到ThreadLocal │
└────────────────────┬────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────┐
│ 返回TransactionInfo │
│ - 包含TransactionStatus │
│ - 绑定到ThreadLocal │
└────────────────────┬────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────┐
│ 执行业务方法: invocation.proceedWithInvocation() │
│ → userRepository.save(user) │
│ │
│ 【业务方法使用同一个Connection执行SQL】 │
└────────────────────┬────────────────────────────────────┘
│
↓ (正常执行)
┌─────────────────────────────────────────────────────────┐
│ commitTransactionAfterReturning() │
│ │
│ → tm.commit(status) │
│ → con.commit() ← 提交事务 │
│ → 释放连接 │
└─────────────────────────────────────────────────────────┘
│
↓ (发生异常)
┌─────────────────────────────────────────────────────────┐
│ completeTransactionAfterThrowing() │
│ │
│ → tm.rollback(status) │
│ → con.rollback() ← 回滚事务 │
│ → 释放连接 │
└─────────────────────────────────────────────────────────┘十、关键问题解答
Q1:为什么一个线程内多次获取的Connection是同一个?
@Transactional
public void method1() {
Connection conn1 = dataSource.getConnection();
method2(); // 同一个类或不同类的另一个事务方法
Connection conn2 = dataSource.getConnection();
// conn1 == conn2 ? YES!
}原因:在doBegin方法中,连接被绑定到了TransactionSynchronizationManager:
TransactionSynchronizationManager.bindResource(
obtainDataSource(), txObject.getConnectionHolder());后续获取连接时,会先从ThreadLocal查找:
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null) {
return conHolder.getConnection(); // 返回已绑定的连接
}这确保了同一个事务内的所有操作使用同一个连接。
Q2:Connection.setAutoCommit(false)的底层做了什么?
这是JDBC规范定义的标准行为:
// MySQL驱动的简化实现
public void setAutoCommit(boolean autoCommit) throws SQLException {
if (this.autoCommit != autoCommit) {
this.autoCommit = autoCommit;
if (!autoCommit) {
// 发送SQL关闭自动提交
execSQL("SET autocommit=0");
} else {
execSQL("SET autocommit=1");
}
}
}效果:
autoCommit=true:每条SQL执行后自动commitautoCommit=false:需要手动调用commit()或rollback()
Q3:事务传播行为REQUIRED和REQUIRES_NEW的区别?
@Service
class ServiceA {
@Autowired ServiceB serviceB;
@Transactional // 事务A
public void methodA() {
// 业务逻辑1
serviceB.methodB(); // 调用ServiceB
// 业务逻辑2 (如果methodB抛异常,这里会怎样?)
}
}
@Service
class ServiceB {
// 情况1: REQUIRED(默认)
@Transactional
public void methodB() {
// 加入事务A,同一个事务
// 如果这里抛异常,事务A也会回滚
}
// 情况2: REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// 挂起事务A,创建新事务B
// 如果这里抛异常,事务B回滚,但事务A可以捕获异常继续执行
}
}核心区别:
REQUIRED:加入现有事务,共用一个ConnectionREQUIRES_NEW:挂起现有事务(解绑Connection),创建新事务(获取新Connection)
十一、总结与伏笔
通过本文的深入分析,我们完整追踪了事务开启的全过程:
- 方法拦截:
TransactionInterceptor.invoke() - 属性解析:从
@Transactional注解提取事务配置 - 管理器查找:确定使用哪个
PlatformTransactionManager - 事务获取:
AbstractPlatformTransactionManager.getTransaction()- 检查是否存在现有事务
- 根据传播行为决定策略
- 事务开启:
DataSourceTransactionManager.doBegin()- 从数据源获取物理连接
- 关闭自动提交:
setAutoCommit(false) - 绑定连接到ThreadLocal
- 信息绑定:将
TransactionInfo绑定到ThreadLocal
但还有几个关键问题尚未解答:
AbstractPlatformTransactionManager的事务生命周期是如何管理的?- 七种传播行为的具体实现
- 事务挂起与恢复的机制
- 事务同步回调的设计
TransactionSynchronizationManager的ThreadLocal机制如何工作?- 资源绑定的底层数据结构
- ConnectionHolder的封装
- 事务完成后的清理
DataSource究竟是什么?连接池如何工作?
- Druid连接池的集成
- 连接的获取与释放
- 连接复用的机制
下一篇预告:《事务管理器的核心:AbstractPlatformTransactionManager的事务生命周期》,我们将深入分析事务管理器的完整生命周期,包括事务的传播、挂起、恢复、提交和回滚。