1. Spring声明式事务的本质理解
第一次接触Spring声明式事务时,很多人会被它简洁的@Transactional注解所迷惑,以为这只是个简单的开关。但当我真正深入源码后才发现,这背后隐藏着一套精密的自动化事务管理机制。声明式事务的核心价值在于,它把原本需要手动编写的事务控制代码(如begin、commit、rollback)转化为元数据配置,让开发者可以专注于业务逻辑。
在Spring框架中,声明式事务是通过AOP(面向切面编程)实现的典型范例。当我们给方法加上@Transactional注解时,实际上是为这个方法打上了"需要事务管理"的标记。Spring容器在启动时,会扫描这些标记,并为这些方法动态生成代理对象。这个代理对象会在方法调用前后自动插入事务管理的逻辑,包括事务的创建、提交和回滚。
关键理解:声明式事务不是魔法,而是Spring框架通过动态代理和AOP技术实现的自动化封装。理解这一点,是后续分析源码的基础。
2. 声明式事务的核心组件解析
2.1 事务拦截器链
Spring事务管理的核心是TransactionInterceptor这个类。它实现了MethodInterceptor接口,是AOP联盟标准中的方法拦截器。当代理对象的方法被调用时,TransactionInterceptor会被触发执行。它的invoke方法大致流程如下:
- 获取方法的事务属性(从@Transactional注解解析而来)
- 创建或加入事务(根据传播行为决定)
- 执行业务方法
- 根据执行结果提交或回滚事务
java复制public Object invoke(MethodInvocation invocation) throws Throwable {
// 获取事务属性
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = tas.getTransactionAttribute(invocation.getMethod(), invocation.getClass());
// 创建或加入事务
TransactionInfo txInfo = createTransactionIfNecessary(txAttr, invocation.getMethod(), invocation.getArguments());
Object retVal;
try {
// 执行业务方法
retVal = invocation.proceed();
}
catch (Throwable ex) {
// 异常处理:决定是否回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
// 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
2.2 事务属性源与注解解析
TransactionAttributeSource接口负责从方法或类上提取事务属性。默认实现是AnnotationTransactionAttributeSource,它专门处理@Transactional注解。解析过程会考虑注解的各个属性:
- propagation:事务传播行为(REQUIRED, REQUIRES_NEW等)
- isolation:事务隔离级别(READ_COMMITTED等)
- timeout:事务超时时间
- readOnly:是否只读事务
- rollbackFor/rollbackForClassName/noRollbackFor/noRollbackForClassName:定义哪些异常触发回滚
java复制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());
int timeout = attributes.getNumber("timeout");
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
rbta.setTimeout(timeout);
}
rbta.setReadOnly(attributes.getBoolean("readOnly"));
// 处理rollback规则
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
// 省略其他rollback规则处理...
rbta.setRollbackRules(rollbackRules);
return rbta;
}
2.3 事务管理器与同步器
PlatformTransactionManager是Spring事务抽象的核心接口,常见实现有:
- DataSourceTransactionManager:用于JDBC和MyBatis等
- HibernateTransactionManager:用于Hibernate
- JpaTransactionManager:用于JPA
- JtaTransactionManager:用于分布式事务
事务同步器(TransactionSynchronizationManager)是一个重要的工具类,它使用ThreadLocal变量来保存当前线程的事务资源(如Connection)和事务状态。这使得在同一线程中,不同的框架组件(如Spring JDBC和MyBatis)可以共享同一个事务上下文。
3. 声明式事务的完整生命周期
3.1 事务的创建与启动
当调用带有@Transactional注解的方法时,Spring会先检查当前是否存在活动事务,这取决于传播行为的设置:
- PROPAGATION_REQUIRED:如果存在事务则加入,否则新建
- PROPAGATION_REQUIRES_NEW:总是新建事务,暂停当前事务(如果有)
- PROPAGATION_NESTED:如果存在事务则在嵌套事务中执行,否则新建
创建新事务的核心逻辑在AbstractPlatformTransactionManager中:
java复制protected TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean newTransaction, boolean newSynchronization, boolean debug) {
// 设置事务超时
if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
prepareTimeout(timeout);
}
}
// 设置隔离级别
Integer previousIsolationLevel = null;
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
previousIsolationLevel = prepareIsolationLevel(definition.getIsolationLevel());
}
// 设置只读标志
boolean readOnly = definition.isReadOnly();
if (readOnly) {
prepareReadOnly();
}
// 设置事务名称(方法名)
String name = definition.getName();
if (name != null) {
prepareName(name);
}
// 执行事务开始逻辑
doBegin(transaction, definition);
// 注册同步(如果需要)
if (newSynchronization) {
prepareSynchronization(status, definition);
}
return status;
}
3.2 事务的提交与回滚
事务提交的核心逻辑在AbstractPlatformTransactionManager.commit()方法中。Spring会先检查事务是否被标记为rollback-only(通常是因为内部方法抛出了异常),如果是则执行回滚而不是提交。
java复制public final void commit(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException("Transaction is already completed");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
if (defStatus.isLocalRollbackOnly()) {
processRollback(defStatus, false);
return;
}
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
processRollback(defStatus, true);
return;
}
processCommit(defStatus);
}
回滚处理则更加复杂,需要考虑异常类型与rollback规则的匹配:
java复制protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
else {
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}
3.3 事务同步与资源管理
Spring使用TransactionSynchronizationManager来管理事务资源,它内部使用ThreadLocal存储以下信息:
- 当前事务的活动资源(如数据库连接)
- 事务同步器(TransactionSynchronization)
- 当前事务的名称、只读状态、隔离级别等
资源绑定的典型流程(以DataSourceTransactionManager为例):
java复制protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = obtainDataSource().getConnection();
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// 设置事务隔离级别
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// 设置只读
if (con.isReadOnly() != definition.isReadOnly()) {
con.setReadOnly(definition.isReadOnly());
}
// 开始事务
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
con.setAutoCommit(false);
}
// 绑定连接到当前线程
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);
}
}
4. 高级特性与内部机制
4.1 事务传播行为的实现细节
不同传播行为的实现主要在TransactionAspectSupport中处理:
java复制protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
status = tm.getTransaction(txAttr);
}
else {
throw new IllegalStateException("No PlatformTransactionManager set");
}
}
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
else {
// 省略CallbackPreferringPlatformTransactionManager处理...
}
}
PROPAGATION_REQUIRES_NEW的实现会挂起当前事务(如果有):
java复制public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
Object transaction = doGetTransaction();
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, null);
if (isExistingTransaction(transaction)) {
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
return startTransaction(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resume(transaction, suspendedResources);
throw beginEx;
}
}
// 处理其他传播行为...
}
// 没有现有事务时的处理...
}
4.2 嵌套事务的实现
PROPAGATION_NESTED的实现依赖于数据库的保存点(Savepoint)功能:
java复制protected void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
if (status.hasSavepoint()) {
status.rollbackToHeldSavepoint();
}
else if (status.isNewTransaction()) {
doRollback(status);
}
else if (status.hasTransaction()) {
if (isGlobalRollbackOnParticipationFailure()) {
doSetRollbackOnly(status);
}
}
}
finally {
cleanupAfterCompletion(status);
}
}
4.3 事务同步器的使用场景
TransactionSynchronization接口允许我们在事务的关键点插入自定义逻辑:
java复制public interface TransactionSynchronization extends Flushable {
int STATUS_COMMITTED = 0;
int STATUS_ROLLED_BACK = 1;
int STATUS_UNKNOWN = 2;
default void suspend() {}
default void resume() {}
default void flush() {}
default void beforeCommit(boolean readOnly) {}
default void beforeCompletion() {}
default void afterCommit() {}
default void afterCompletion(int status) {}
}
典型使用场景包括:
- 在事务提交后发送事件或消息
- 在事务回滚后进行补偿操作
- 实现类似"事务性缓存"的功能
5. 常见问题与调试技巧
5.1 事务不生效的常见原因
-
方法可见性问题:动态代理要求方法至少是protected级别(CGLIB代理)或public(JDK代理)
-
自调用问题:同一个类中方法A调用方法B,即使B有@Transactional也不会生效
java复制@Service
public class UserService {
public void methodA() {
this.methodB(); // 事务不生效
}
@Transactional
public void methodB() {
// ...
}
}
-
异常被捕获:异常必须在传播到事务拦截器时未被捕获
-
数据库引擎不支持:如MyISAM引擎不支持事务
-
错误的传播行为:如PROPAGATION_SUPPORTS在没有事务时不会创建新事务
5.2 事务调试技巧
- 开启调试日志:
properties复制logging.level.org.springframework.transaction=DEBUG
logging.level.org.springframework.jdbc.datasource=DEBUG
- 检查代理类型:
java复制@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
// 检查Bean是否是代理对象
System.out.println(ctx.getBean("userService").getClass());
}
}
- 使用TransactionSynchronizationManager调试:
java复制@Transactional
public void someMethod() {
System.out.println("Current transaction active: " +
TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("Current transaction name: " +
TransactionSynchronizationManager.getCurrentTransactionName());
}
5.3 性能优化建议
-
合理设置事务超时:避免长时间占用数据库连接
-
正确使用只读事务:对查询操作使用@Transactional(readOnly=true)
-
避免大事务:将大事务拆分为多个小事务
-
谨慎使用PROPAGATION_REQUIRES_NEW:它会挂起当前事务,可能导致锁等待
-
合理配置隔离级别:默认的READ_COMMITTED在大多数场景下已经足够
6. 源码阅读路线建议
对于想要深入理解Spring事务实现的开发者,我建议按以下顺序阅读源码:
-
注解解析层:
- AnnotationTransactionAttributeSource
- SpringTransactionAnnotationParser
- JtaTransactionAnnotationParser
-
AOP代理层:
- ProxyTransactionManagementConfiguration
- TransactionInterceptor
- TransactionAspectSupport
-
事务管理层:
- PlatformTransactionManager接口
- AbstractPlatformTransactionManager
- DataSourceTransactionManager
-
资源同步层:
- TransactionSynchronizationManager
- TransactionSynchronization
-
事务定义与状态:
- TransactionDefinition
- TransactionStatus
- DefaultTransactionStatus
在阅读源码时,重点关注以下几个关键流程:
- 代理对象的创建过程
- 事务属性的解析过程
- 事务的创建与启动流程
- 事务的提交与回滚决策
- 资源绑定与释放的时机