很多人都会使用 @Transactional 注解,但对于其背后的运行机制,能清晰回答以下问题的人却不多:
@Transactional 是怎么被拦截的?
- 事务什么时候创建?数据库连接又是在哪一步获取的?
- 为什么在同一个事务内,MyBatis 或 JdbcTemplate 总能拿到同一条 Connection?
- 最终的回滚和提交操作,究竟是谁来执行的?
- 关键的
ThreadLocal 又在哪个环节发挥了作用?
这篇文章不会重复讲解 API 如何使用,而是带你深入源码,完整走一遍 @Transactional 的生命周期,看清它究竟是如何“跑”起来的。
@Transactional 并非“魔法”,本质是 AOP
首先需要明确,Spring 的事务管理能力并非 JVM 或 JDBC 层自带的,而是 AOP(面向切面编程)与事务管理器协同工作的结果。
整个流程的核心入口只有一个:
TransactionInterceptor
一、TransactionInterceptor 拦截执行
所有被 @Transactional 注解标记的方法调用,最终都会由 TransactionInterceptor 这个 AOP 增强拦截器进行处理。
// 位置:org.springframework.transaction.interceptor.TransactionInterceptor
public class TransactionInterceptor extends TransactionAspectSupport
implements MethodInterceptor, Serializable {
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// 获取目标类
Class<?> targetClass = (invocation.getThis() != null ?
AopUtils.getTargetClass(invocation.getThis()) : null);
// ⭐ 调用父类的事务处理方法
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed(); // 执行目标方法
}
});
}
}
可以看到,它直接调用了父类 TransactionAspectSupport 的 invokeWithinTransaction 方法,这是整个事务处理逻辑的起点。
二、事务核心处理逻辑
真正的“魔法”发生在 TransactionAspectSupport.invokeWithinTransaction() 方法中。这个方法定义了事务处理的骨架。
// 位置:org.springframework.transaction.interceptor.TransactionAspectSupport
// 这是整个事务处理的核心方法,约在第 340 行
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// ========== 第一步:获取事务属性 ==========
TransactionAttributeSource tas = getTransactionAttributeSource();
// 解析 @Transactional 注解的属性(传播行为、隔离级别、超时等)
final TransactionAttribute txAttr = (tas != null ?
tas.getTransactionAttribute(method, targetClass) : null);
// ========== 第二步:确定事务管理器 ==========
final TransactionManager tm = determineTransactionManager(txAttr);
// 响应式事务处理(WebFlux)
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager rtm) {
// ... 响应式处理逻辑
}
// ========== 第三步:转换为 PlatformTransactionManager ==========
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager cpptm)) {
// ========== 第四步:创建事务 ==========
// ⭐⭐⭐ 这里开始创建/获取事务,并绑定 DataSource 到 ThreadLocal
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 && txAttr != null) {
// 处理 Vavr Try 返回值
// ...
}
// ========== 第八步:提交事务 ==========
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// CallbackPreferringPlatformTransactionManager 处理
// ...
}
}
这个骨架清晰地勾勒出了事务的八大步骤。接下来,我们深入几个关键环节。
2.1 确定事务管理器 (determineTransactionManager)
事务管理器 (PlatformTransactionManager) 是执行具体事务操作(如获取连接、提交、回滚)的实体。Spring 通过 determineTransactionManager 方法来确定使用哪一个。
protected TransactionManager determineTransactionManager(
@Nullable TransactionAttribute txAttr, @Nullable Class<?> targetClass) {
// ==================== 第一步:尝试从事务属性中获取 ====================
// 调用已废弃的重载方法,用于向后兼容
// 如果 @Transactional(transactionManager = "xxx") 指定了事务管理器名称,会在这里处理
TransactionManager tm = determineTransactionManager(txAttr);
if (tm != null) {
return tm;
}
// ==================== 第二步:检查前置条件 ====================
// 如果没有事务属性或没有 BeanFactory,直接返回默认事务管理器
// 这种情况通常发生在非事务方法或手动配置场景
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager(); // 返回通过 setter 注入的默认事务管理器
}
// ==================== 第三步:通过 qualifier 限定符查找 ====================
// 获取 @Transactional 注解中的 qualifier 属性
// 例如: @Transactional(value = "order") 或 @Transactional("order")
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
// 通过 qualifier 从 BeanFactory 中获取指定的事务管理器
// 对应的 Bean 需要用 @Qualifier("order") 或 @Bean("order") 标注
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}
// ==================== 第四步:检查目标类上的 @Qualifier 注解 ====================
else if (targetClass != null) {
// 查找目标类上是否有 @Qualifier 注解
// 例如: @Qualifier("order") @Service public class OrderService { ... }
String typeQualifier = BeanFactoryAnnotationUtils.getQualifierValue(targetClass);
if (StringUtils.hasText(typeQualifier)) {
try {
return determineQualifiedTransactionManager(this.beanFactory, typeQualifier);
}
catch (NoSuchBeanDefinitionException ex) {
// 类级别的 qualifier 是可选的,找不到时继续往下查找
// 不抛出异常,而是使用常规解析逻辑
}
}
}
// ==================== 第五步:通过配置的 Bean 名称查找 ====================
// 检查是否通过 setTransactionManagerBeanName() 设置了事务管理器的 Bean 名称
if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
}
// ==================== 第六步:获取默认事务管理器(兜底逻辑) ====================
else {
// 首先尝试获取通过 setter 直接注入的事务管理器
TransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
// 尝试从缓存中获取(避免重复查找)
defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
// ⭐⭐⭐ 核心:从 Spring 容器中按类型获取 TransactionManager
// 这里会获取到 Spring Boot 自动配置的 JdbcTransactionManager
// JdbcTransactionManager 是在 DataSourceTransactionManagerAutoConfiguration 中创建的
// 它持有 HikariDataSource 的引用
defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);
// 放入缓存,下次直接使用
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}
在 Spring Boot 默认的单数据源场景下,最终会通过 this.beanFactory.getBean(TransactionManager.class) 拿到容器中唯一的 JdbcTransactionManager。
Spring Boot 启动
↓
DataSourceAutoConfiguration
↓ 创建 HikariDataSource 并注入容器
↓
DataSourceTransactionManagerAutoConfiguration
↓ @ConditionalOnSingleCandidate(DataSource.class) → 检测到 HikariDataSource
↓ @ConditionalOnMissingBean(TransactionManager.class) → 没有自定义事务管理器
↓
JdbcTransactionManagerConfiguration.transactionManager()
↓ 检查 spring.dao.exceptiontranslation.enabled (默认 true)
↓
new JdbcTransactionManager(dataSource) ⭐ 创建并注入容器
↓
↓ 注册 Bean 名称为 "transactionManager"
↓
TransactionAspectSupport.determineTransactionManager()
↓ this.beanFactory.getBean(TransactionManager.class)
↓
返回 JdbcTransactionManager 实例
其自动配置源码如下:
// 位置:org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
// Spring Boot 3.x 源码
@AutoConfiguration(after = { DataSourceAutoConfiguration.class })
@ConditionalOnClass({ JdbcTemplate.class, TransactionManager.class })
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceTransactionManagerAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnSingleCandidate(DataSource.class) // 存在唯一 DataSource 时生效
static class JdbcTransactionManagerConfiguration {
@Bean
@ConditionalOnMissingBean(TransactionManager.class) // 没有自定义事务管理器时才创建
// ⭐⭐⭐ 这里创建的就是 JdbcTransactionManager(Spring Boot 3.x)
// 而不是 DataSourceTransactionManager
DataSourceTransactionManager transactionManager(
Environment environment,
DataSource dataSource, // 注入 HikariDataSource
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
// ⭐ 关键:createTransactionManager 方法
DataSourceTransactionManager transactionManager = createTransactionManager(environment, dataSource);
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
return transactionManager;
}
private DataSourceTransactionManager createTransactionManager(Environment environment, DataSource dataSource) {
return environment.getProperty("spring.dao.exceptiontranslation.enabled", Boolean.class, Boolean.TRUE)
? new JdbcTransactionManager(dataSource) : new DataSourceTransactionManager(dataSource);
}
}
}
2.2 createTransactionIfNecessary() - 创建事务
确定事务管理器后,便调用 createTransactionIfNecessary 来准备事务。
// 位置:TransactionAspectSupport 第 620 行左右
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// 包装事务属性
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);
}
}
// 准备事务信息并绑定到当前线程
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
这里的关键是 tm.getTransaction(txAttr),它委托给具体的事务管理器来开启或加入一个事务。
三、事务管理器获取/创建事务(DataSource 绑定的关键)
3.1 getTransaction
AbstractPlatformTransactionManager.getTransaction() 是事务获取的模板方法,处理了事务传播行为等核心逻辑。
// 位置:org.springframework.transaction.support.AbstractPlatformTransactionManager
// 约在第 370 行
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
// ⭐ 第一步:获取当前事务对象(检查是否已有事务)
Object transaction = doGetTransaction(); // 由子类 DataSourceTransactionManager 实现
boolean debugEnabled = logger.isDebugEnabled();
// ⭐ 第二步:检查是否已存在事务
if (isExistingTransaction(transaction)) {
// 根据传播行为处理已存在的事务
return handleExistingTransaction(def, transaction, debugEnabled);
}
// ========== 以下是不存在事务的情况 ==========
// 检查超时
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// MANDATORY:必须在事务中运行,否则抛异常
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
// 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);
try {
// ⭐⭐⭐ 开启新事务
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
// SUPPORTS、NOT_SUPPORTED、NEVER:创建“空”事务
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated...");
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
3.2 startTransaction() - 开启新事务
对于需要新事务的情况,会进入 startTransaction 方法。
// 位置:AbstractPlatformTransactionManager 约第 400 行
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);
// ⭐⭐⭐ 核心:真正开始事务(由子类实现)
doBegin(transaction, definition);
// 准备事务同步(初始化 TransactionSynchronizationManager)
prepareSynchronization(status, definition);
return status;
}
doBegin(transaction, definition) 是一个抽象方法,由具体的事务管理器实现。对于 JDBC 事务,就是 DataSourceTransactionManager.doBegin()。这里也是数据库连接获取和绑定的核心。
3.3 DataSourceTransactionManager.doGetTransaction() - 获取事务对象
在判断是否存在事务时,会调用 doGetTransaction()。
// 位置:org.springframework.jdbc.datasource.DataSourceTransactionManager
// 约第 220 行
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// ⭐⭐⭐ 关键:从 TransactionSynchronizationManager 获取当前线程绑定的 ConnectionHolder
// 如果之前已经在事务中,这里会获取到已有的连接
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager
.getResource(obtainDataSource()); // obtainDataSource() 返回 HikariDataSource
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
这个方法第一次揭示了 TransactionSynchronizationManager 的作用:它像一个注册中心,存储着当前线程与事务相关的资源(如数据库连接)。
3.4 DataSourceTransactionManager.doBegin() - 真正开启事务 (DataSource 绑定时机)
这是整个流程中最关键的方法之一,数据库连接的获取、事务的开启(关闭自动提交)、以及资源与线程的绑定都在这里发生。
// 位置:DataSourceTransactionManager 约第 260 行
// ⭐⭐⭐ 这是 DataSource 绑定到 TransactionSynchronizationManager 的关键方法
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// ========== 第一步:获取数据库连接 ==========
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// ⭐⭐⭐ 从 DataSource(HikariDataSource)获取新连接
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
// 创建新的 ConnectionHolder 并标记为新连接
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// ========== 第二步:准备连接(设置隔离级别、只读等) ==========
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
txObject.setReadOnly(definition.isReadOnly());
// ========== 第三步:关闭自动提交(开启事务的本质) ==========
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
// ⭐⭐⭐ JDBC 层面开启事务的本质:关闭自动提交
con.setAutoCommit(false);
}
// 准备事务连接(设置只读等)
prepareTransactionalConnection(con, definition);
// 标记事务为活跃状态
txObject.getConnectionHolder().setTransactionActive(true);
// ========== 第四步:设置超时 ==========
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// ========== ⭐⭐⭐ 第五步:绑定 DataSource 和 ConnectionHolder 到 TransactionSynchronizationManager ==========
if (txObject.isNewConnectionHolder()) {
// 这是关键!!!将 DataSource -> ConnectionHolder 的映射绑定到当前线程
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);
}
}
核心点:在第5步,通过 TransactionSynchronizationManager.bindResource(),将 DataSource 和代表数据库连接的 ConnectionHolder 绑定到了当前线程。这保证了后续在同一个线程内,任何需要数据库连接的地方,都能通过同一个 DataSource 键获取到这个特定的连接。
四、TransactionSynchronizationManager - 线程绑定管理
4.1 资源绑定核心实现
TransactionSynchronizationManager 是 Spring 事务同步管理的核心工具类,它内部使用 ThreadLocal 来保存线程隔离的事务资源。
// 位置:org.springframework.transaction.support.TransactionSynchronizationManager
public abstract class TransactionSynchronizationManager {
// ⭐⭐⭐ 核心:使用 ThreadLocal 存储资源(DataSource -> ConnectionHolder)
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
// 事务同步器列表
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
// 当前事务名称
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
// 当前事务只读标志
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
// 当前事务隔离级别
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
// 事务是否激活
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
// ========== 资源绑定方法 ==========
/**
* ⭐⭐⭐ 绑定资源到当前线程
* 在 DataSourceTransactionManager.doBegin() 中调用
* key = HikariDataSource, value = ConnectionHolder
*/
public static void bindResource(Object key, Object value) throws IllegalStateException {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
Map<Object, Object> map = resources.get();
if (map == null) {
map = new HashMap<>();
resources.set(map);
}
Object oldValue = map.put(actualKey, value);
if (oldValue instanceof ResourceHolder resourceHolder && resourceHolder.isVoid()) {
oldValue = null;
}
if (oldValue != null) {
throw new IllegalStateException(
"Already value [" + oldValue + "] for key [" + actualKey + "] bound to thread");
}
}
/**
* ⭐⭐⭐ 获取当前线程绑定的资源
* MyBatis/JdbcTemplate 获取连接时会调用此方法
*/
@Nullable
public static Object getResource(Object key) {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
return doGetResource(actualKey);
}
@Nullable
private static Object doGetResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.get(actualKey);
if (value instanceof ResourceHolder resourceHolder && resourceHolder.isVoid()) {
map.remove(actualKey);
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}
/**
* 解绑资源(事务结束时调用)
*/
public static Object unbindResource(Object key) throws IllegalStateException {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Object value = doUnbindResource(actualKey);
if (value == null) {
throw new IllegalStateException("No value for key [" + actualKey + "] bound to thread");
}
return value;
}
}
正是通过这个 ThreadLocal<Map> 结构,Spring 实现了事务资源(尤其是数据库连接)的线程绑定,这是保证同一事务内操作使用同一连接的核心机制。理解这个机制,对于处理复杂的并发和连接池问题至关重要,更多关于 Java 并发与资源管理的深入探讨,可以在相关社区找到。
五、MyBatis 如何获取事务中的连接
当业务方法中通过 MyBatis 执行 SQL 时,它是如何拿到那个被绑定到当前线程的 Connection 的呢?
5.1 SpringManagedTransaction(MyBatis-Spring)
MyBatis-Spring 整合包提供了一个 SpringManagedTransaction,它替代了 MyBatis 默认的事务管理。
// 位置:org.mybatis.spring.transaction.SpringManagedTransaction
public class SpringManagedTransaction implements Transaction {
private final DataSource dataSource;
private Connection connection;
private boolean isConnectionTransactional;
private boolean autoCommit;
public SpringManagedTransaction(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public Connection getConnection() throws SQLException {
if (this.connection == null) {
openConnection();
}
return this.connection;
}
private void openConnection() throws SQLException {
// ⭐⭐⭐ 关键:通过 DataSourceUtils 获取连接
// 如果当前线程在事务中,会返回 TransactionSynchronizationManager 中绑定的连接
this.connection = DataSourceUtils.getConnection(this.dataSource);
this.autoCommit = this.connection.getAutoCommit();
this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
}
@Override
public void commit() throws SQLException {
// 如果连接是事务管理的,不在这里提交(由 Spring 事务管理器提交)
if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
this.connection.commit();
}
}
@Override
public void rollback() throws SQLException {
// 同上,由 Spring 事务管理器回滚
if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
this.connection.rollback();
}
}
}
可以看到,它把获取连接的工作委托给了 Spring 的 DataSourceUtils.getConnection()。
5.2 DataSourceUtils.getConnection() - 获取连接的核心
这是连接获取的统一门户,无论是 MyBatis 还是 JdbcTemplate,最终都会走到这里。
// 位置:org.springframework.jdbc.datasource.DataSourceUtils
public abstract class DataSourceUtils {
/**
* ⭐⭐⭐ 获取数据库连接
* 如果当前线程在事务中,返回事务绑定的连接
* 否则从 DataSource 获取新连接
*/
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
try {
return doGetConnection(dataSource);
}
catch (SQLException ex) {
throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex);
}
catch (IllegalStateException ex) {
throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex);
}
}
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
// ⭐⭐⭐ 关键:从 TransactionSynchronizationManager 获取当前线程绑定的 ConnectionHolder
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
// 如果存在绑定的连接,直接返回(保证事务中使用同一个连接)
if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
conHolder.setConnection(fetchConnection(dataSource));
}
return conHolder.getConnection(); // ⭐ 返回事务中的连接
}
// 没有绑定连接,从 DataSource 获取新连接
Connection con = fetchConnection(dataSource);
// 如果当前有事务同步激活,注册同步器
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// ...
}
return con;
}
}
逻辑非常清晰:首先尝试从 TransactionSynchronizationManager 中获取当前线程绑定的 ConnectionHolder。如果存在(说明当前正在事务中),则直接返回其中的 Connection;如果不存在,才从数据源获取一个新的连接。这就完美解释了为何事务内的数据库操作总是使用同一个连接。
六、事务提交与回滚
业务方法执行完毕后,根据是否发生异常,决定是提交还是回滚。
6.1 提交事务
// 位置:TransactionAspectSupport
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
// 位置:AbstractPlatformTransactionManager
@Override
public final void commit(TransactionStatus status) throws TransactionException {
// ...
processCommit(defStatus);
}
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
// 触发 beforeCommit 回调
triggerBeforeCommit(status);
// 触发 beforeCompletion 回调
triggerBeforeCompletion(status);
if (status.isNewTransaction()) {
// ⭐ 真正提交事务
doCommit(status);
}
// ...
}
finally {
cleanupAfterCompletion(status);
}
}
// 位置:DataSourceTransactionManager
@Override
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
try {
// ⭐⭐⭐ JDBC 提交
con.commit();
}
catch (SQLException ex) {
throw translateException("JDBC commit", ex);
}
}
6.2 回滚事务
// 位置:TransactionAspectSupport
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
// 判断是否需要回滚(默认只回滚 RuntimeException 和 Error)
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
else {
// 不回滚,正常提交
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
}
// 位置:DataSourceTransactionManager
@Override
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
try {
// ⭐⭐⭐ JDBC 回滚
con.rollback();
}
catch (SQLException ex) {
throw translateException("JDBC rollback", ex);
}
}
6.3 清理资源
无论提交还是回滚,最后都必须清理资源,将连接归还给连接池,并解除线程绑定。
// 位置:AbstractPlatformTransactionManager
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
// 清理 TransactionSynchronizationManager
TransactionSynchronizationManager.clear();
}
if (status.isNewTransaction()) {
// ⭐ 清理事务资源
doCleanupAfterCompletion(status.getTransaction());
}
if (status.getSuspendedResources() != null) {
// 恢复挂起的事务
resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
// 位置:DataSourceTransactionManager
@Override
protected void doCleanupAfterCompletion(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
if (txObject.isNewConnectionHolder()) {
// ⭐⭐⭐ 从 TransactionSynchronizationManager 解绑 DataSource
TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
Connection con = txObject.getConnectionHolder().getConnection();
try {
// 恢复自动提交
if (txObject.isMustRestoreAutoCommit()) {
con.setAutoCommit(true);
}
// 重置连接状态
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
}
catch (Throwable ex) {
logger.debug("Could not reset JDBC Connection after transaction", ex);
}
if (txObject.isNewConnectionHolder()) {
// ⭐ 释放连接回连接池
DataSourceUtils.releaseConnection(con, this.dataSource);
}
txObject.getConnectionHolder().clear();
}
七、完整流程图总结
最后,我们用一张完整的流程图来串联整个 @Transactional 的执行过程,这有助于你从全局视角理解 Spring 事务管理的 AOP 设计思想。
┌─────────────────────────────────────────────────────────────────────────────┐
│ @Transactional 完整执行流程 │
└─────────────────────────────────────────────────────────────────────────────┘
1. Spring Boot 启动阶段
┌──────────────────────────────────────────────────────────────────────────┐
│ TransactionAutoConfiguration │
│ └── @EnableTransactionManagement │
│ └── ProxyTransactionManagementConfiguration │
│ ├── TransactionInterceptor (Bean) │
│ └── BeanFactoryTransactionAttributeSourceAdvisor (Bean) │
│ │
│ DataSourceTransactionManagerAutoConfiguration │
│ └── DataSourceTransactionManager (Bean) │
│ └── 注入 HikariDataSource │
└──────────────────────────────────────────────────────────────────────────┘
↓
2. Bean 创建阶段(对 @Transactional 标注的类创建代理)
┌──────────────────────────────────────────────────────────────────────────┐
│ AbstractAutoProxyCreator.postProcessAfterInitialization() │
│ └── wrapIfNecessary() │
│ └── createProxy() → 返回 CGLIB 代理对象 │
└──────────────────────────────────────────────────────────────────────────┘
↓
3. 方法调用阶段
┌──────────────────────────────────────────────────────────────────────────┐
│ 调用 @Transactional 方法 │
│ ↓ │
│ CglibAopProxy.DynamicAdvisedInterceptor.intercept() │
│ ↓ │
│ TransactionInterceptor.invoke() │
│ ↓ │
│ TransactionAspectSupport.invokeWithinTransaction() │
└──────────────────────────────────────────────────────────────────────────┘
↓
4. 创建/获取事务
┌──────────────────────────────────────────────────────────────────────────┐
│ TransactionAspectSupport.createTransactionIfNecessary() │
│ ↓ │
│ AbstractPlatformTransactionManager.getTransaction() │
│ ├── doGetTransaction() → 检查是否已有事务 │
│ └── startTransaction() │
│ ↓ │
│ DataSourceTransactionManager.doBegin() │
│ ├── dataSource.getConnection() → 从 HikariPool 获取连接 │
│ ├── connection.setAutoCommit(false) → 开启事务 │
│ └── TransactionSynchronizationManager.bindResource() │
│ ↓ │
│ ⭐ 将 HikariDataSource -> ConnectionHolder 绑定到 ThreadLocal │
└──────────────────────────────────────────────────────────────────────────┘
↓
5. 执行业务方法(MyBatis 获取连接)
┌──────────────────────────────────────────────────────────────────────────┐
│ invocation.proceedWithInvocation() → 执行目标方法 │
│ ↓ │
│ MyBatis Mapper 执行 SQL │
│ ↓ │
│ SpringManagedTransaction.getConnection() │
│ ↓ │
│ DataSourceUtils.getConnection(dataSource) │
│ ↓ │
│ TransactionSynchronizationManager.getResource(dataSource) │
│ ↓ │
│ ⭐ 返回步骤4绑定的 ConnectionHolder 中的 Connection(同一个连接!) │
└──────────────────────────────────────────────────────────────────────────┘
↓
6. 事务提交或回滚
┌──────────────────────────────────────────────────────────────────────────┐
│ 正常完成: │
│ commitTransactionAfterReturning() │
│ → DataSourceTransactionManager.doCommit() │
│ → connection.commit() │
│ │
│ 异常发生: │
│ completeTransactionAfterThrowing() │
│ → DataSourceTransactionManager.doRollback() │
│ → connection.rollback() │
└──────────────────────────────────────────────────────────────────────────┘
↓
7. 清理资源
┌──────────────────────────────────────────────────────────────────────────┐
│ cleanupAfterCompletion() │
│ ↓ │
│ DataSourceTransactionManager.doCleanupAfterCompletion() │
│ ├── TransactionSynchronizationManager.unbindResource() → 解绑 │
│ ├── connection.setAutoCommit(true) → 恢复自动提交 │
│ └── DataSourceUtils.releaseConnection() → 归还连接到 HikariPool │
└──────────────────────────────────────────────────────────────────────────┘
希望通过这篇源码级别的剖析,能让你对 Spring @Transactional 事务的管理机制有一个透彻的理解。从 AOP 拦截,到事务管理器的协调,再到通过 ThreadLocal 实现的线程资源绑定,每一个环节都体现了 Spring 框架精妙的设计。掌握这些底层原理,将帮助你更好地使用和调试基于 数据库/中间件 的 Spring 事务,写出更健壮的应用。如果你想与其他开发者深入交流这类技术细节,欢迎到 云栈社区 参与讨论。