1. Spring声明式事务源码全景解析
从事Java开发这些年,我处理过最频繁的问题就是事务管理。Spring声明式事务用起来简单,但真正理解其内部机制的人并不多。今天我们就从源码层面,完整拆解@Transactional注解背后的执行流程。
先看一个典型场景:电商系统中用户下单需要同时操作订单表和库存表,这两个操作必须作为一个原子单元。如果只用JDBC原生事务,我们需要手动获取连接、开启事务、提交/回滚,代码会非常臃肿。而Spring声明式事务通过AOP代理,让我们用简单的注解就能实现复杂的事务控制。
2. 核心组件协作机制
2.1 事务拦截器链
Spring事务的核心是TransactionInterceptor,它实现了MethodInterceptor接口。当调用@Transactional方法时,实际调用链是这样的:
java复制// 伪代码展示调用流程
public Object invoke(MethodInvocation invocation) {
// 1. 获取事务属性
TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(
invocation.getMethod(), invocation.getThis().getClass());
// 2. 创建事务
TransactionInfo txInfo = createTransactionIfNecessary(txAttr, method, clazz);
try {
// 3. 执行目标方法
Object retVal = invocation.proceed();
// 4. 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
} catch (Exception ex) {
// 5. 异常回滚处理
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
}
关键点在于TransactionAttributeSource,它负责解析@Transactional注解属性,包括:
- isolation:隔离级别(默认ISOLATION_DEFAULT)
- propagation:传播行为(默认PROPAGATION_REQUIRED)
- timeout:超时时间(默认-1)
- readOnly:是否只读(默认false)
- rollbackFor:触发回滚的异常类型
2.2 事务管理器体系
PlatformTransactionManager是事务处理的核心接口,常见实现类有:
- DataSourceTransactionManager:用于JDBC和MyBatis
- HibernateTransactionManager:用于Hibernate
- JpaTransactionManager:用于JPA
- JtaTransactionManager:用于分布式事务
以DataSourceTransactionManager为例,其核心方法是:
java复制protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// 获取数据库连接
con = obtainDataSource().getConnection();
// 设置隔离级别
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(
con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// 关闭自动提交
if (con.getAutoCommit()) {
con.setAutoCommit(false);
}
// 设置超时
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
} catch (Throwable ex) {
DataSourceUtils.releaseConnection(con, getDataSource());
throw new CannotCreateTransactionException(...);
}
}
3. 事务传播行为实现细节
3.1 七种传播行为解析
Spring定义了七种事务传播行为,源码中体现在TransactionDefinition接口:
java复制public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
// 其他方法...
}
重点分析PROPAGATION_REQUIRES_NEW的实现逻辑:
java复制if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
// 挂起当前事务
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
// 创建新事务
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 执行事务开始逻辑
doBegin(transaction, definition);
return status;
} catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
3.2 嵌套事务的特殊处理
PROPAGATION_NESTED的实现比较特殊,它使用保存点(Savepoint)机制:
java复制if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(...);
}
// 创建保存点
Object savepoint = txObject.createSavepoint();
txObject.setSavepoint(savepoint);
return prepareTransactionStatus(
definition, transaction, false, newSynchronization, debugEnabled, null, savepoint);
}
当内部事务回滚时,只会回滚到保存点位置,不会影响外部事务:
java复制if (status.hasSavepoint()) {
// 嵌套事务回滚到保存点
status.rollbackToHeldSavepoint();
} else if (status.isNewTransaction()) {
// 独立事务完全回滚
doRollback(status);
} else {
// 参与现有事务,标记为仅回滚
if (status.hasTransaction()) {
status.setRollbackOnly();
}
}
4. 事务同步与资源管理
4.1 同步回调机制
TransactionSynchronizationManager维护了线程绑定的资源Map和同步回调列表。典型应用场景是:
java复制// Session同步回调示例
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronization() {
@Override
public void afterCommit() {
// 事务提交后刷新Session
session.flush();
}
});
4.2 连接资源绑定
DataSourceUtils关键方法解析:
java复制public static Connection doGetConnection(DataSource dataSource) throws SQLException {
// 1. 先从线程上下文获取已有连接
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null) {
return conHolder.getConnection();
}
// 2. 新建连接并绑定到线程
Connection con = dataSource.getConnection();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
ConnectionHolder holderToUse = conHolder;
if (holderToUse == null) {
holderToUse = new ConnectionHolder(con);
}
TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
}
return con;
}
5. 典型问题排查指南
5.1 事务不生效的常见原因
-
代理失效场景:
- 同类方法调用(this.method())
- 非public方法
- final/static方法
- 自调用(@Async同理)
-
异常处理不当:
java复制try { userService.update(user); // @Transactional方法 } catch (Exception e) { // 捕获异常导致事务拦截器无法处理 log.error("更新失败", e); } -
数据库引擎不支持:
- MyISAM引擎不支持事务
- 某些NoSQL数据库无事务概念
5.2 性能优化建议
-
连接池配置:
yaml复制spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000 -
只读事务优化:
java复制@Transactional(readOnly = true) public List<User> queryUsers() { // 查询操作 } -
超时设置:
java复制@Transactional(timeout = 5) // 单位:秒 public void batchProcess() { // 批量操作 }
6. 高级特性解析
6.1 事务事件监听
Spring 4.2+支持事务事件监听:
java复制@Component
public class TransactionListener {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleCommit(TransactionCompletedEvent event) {
// 事务提交后处理
}
}
6.2 编程式事务控制
模板方法的使用示例:
java复制transactionTemplate.execute(status -> {
try {
// 业务逻辑
return result;
} catch (Exception e) {
status.setRollbackOnly();
throw e;
}
});
7. 源码调试技巧
-
关键断点位置:
- TransactionAspectSupport#invokeWithinTransaction
- AbstractPlatformTransactionManager#getTransaction
- DataSourceTransactionManager#doBegin
-
日志配置:
properties复制logging.level.org.springframework.transaction=DEBUG logging.level.org.springframework.jdbc.datasource=TRACE -
事务可视化工具:
- Spring Boot Actuator的/actuator/beans端点
- Arthas的watch命令监控事务状态
理解Spring事务源码的关键在于把握三个核心:
- 代理机制(AOP实现)
- 线程绑定(TransactionSynchronizationManager)
- 模板方法(PlatformTransactionManager)
在实际项目中,建议结合具体业务场景选择合适的事务传播行为,并注意事务边界的合理划分。对于高性能场景,可以考虑将大事务拆分为多个小事务,或使用乐观锁替代悲观锁。
