Spring 的声明式事务管理通过 @Transactional 注解让开发者无需手写事务控制逻辑,其底层由 Spring AOP 和 TransactionInterceptor 实现。本文将基于源码,简单说明事务异常回滚机制
【Spring】声明式事务管理(一)
【Spring】声明式事务管理(二)
一、Java 中实现事务的 3 种方式
方式 | 场景 | 关键 API / 注解 |
---|---|---|
Jdbc 编程式 | 单数据源,最底层 | Connection#setAutoCommit(false) / commit() / rollback() |
Spring 编程式 | 单数据源,模板化 | TransactionTemplate.execute(...) |
Spring 声明式 | 单/多数据源,日常首选 | @Transactional |
二、Spring 声明式事务源码分析
1、开启Spring 声明式事务的总开关是 @EnableTransactionManagement
@Configuration
@EnableTransactionManagement // ① 总开关
@ComponentScan
public class AppConfig {
@Bean
public PlatformTransactionManager txManager(DataSource ds) {
return new DataSourceTransactionManager(ds); // ② 具体策略
}
}
@EnableTransactionManagement 通过 @Import(TransactionManagementConfigurationSelector.class) 将 AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration 注入容器
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
/**
* 1、导入 TransactionManagementConfigurationSelector 配置类
*/
@Import({TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Integer.MAX_VALUE;
}
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
public TransactionManagementConfigurationSelector() {
}
/**
* 2、获取 AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration 全限定名
*/
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[]{this.determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return ClassUtils.isPresent("javax.transaction.Transactional", this.getClass().getClassLoader()) ? "org.springframework.transaction.aspectj.AspectJJtaTransactionManagementConfiguration" : "org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration";
}
}
ProxyTransactionManagementConfiguration 声明了 3 个基础设施 Bean,这 3 个 Bean 分别负责组装 AOP、获取切入点、方法拦截器。核心的事务处理逻辑在 TransactionInterceptor 内
Bean 名称 | 作用 |
---|---|
BeanFactoryTransactionAttributeSourceAdvisor | Advisor(Pointcut + Advice) |
AnnotationTransactionAttributeSource | 解析 @Transactional 的 Pointcut |
TransactionInterceptor | 执行事务逻辑的 Advice |
@Configuration(
proxyBeanMethods = false
)
@Role(2)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
public ProxyTransactionManagementConfiguration() {
}
/**
* 1、将事务的切入点和拦截器绑定在一起
* 相当于于 @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
* +
* TransactionInterceptor 拦截
*/
@Bean(
name = {"org.springframework.transaction.config.internalTransactionAdvisor"}
)
@Role(2)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder((Integer)this.enableTx.getNumber("order"));
}
return advisor;
}
/**
* 2、事务的切入点
*/
@Bean
@Role(2)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
/**
* 3、事务拦截器,切入后执行的动作
*/
@Bean
@Role(2)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
TransactionInterceptor 在执行代理方法时,如果存在异常,就会调用事务管理器的 rollback 方法回滚
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
@Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
// 携带事务执行方法
return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new TransactionAspectSupport.CoroutinesInvocationCallback() {
...
});
}
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
TransactionAttributeSource tas = this.getTransactionAttributeSource();
TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;
// 根据注解获取事务管理器
TransactionManager tm = this.determineTransactionManager(txAttr);
...
Object retVal;
try {
// 执行代理方法
retVal = invocation.proceedWithInvocation();
} catch (Throwable var20) {
// 遇到异常触发回滚
this.completeTransactionAfterThrowing(txInfo, var20);
throw var20;
} finally {
this.cleanupTransactionInfo(txInfo);
}
}
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
...
// 调用事务管理器的回滚方法
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
...
}
}
DataSourceTransactionManager 是事务管理器实现类之一,它的回滚方法其实用的也是 con.rollback()
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
/**
* rollback 调用 doRollback 来回滚
*/
@Override
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
// 撤消当前事务中所做的所有更改
con.rollback();
}
catch (SQLException ex) {
throw translateException("JDBC rollback", ex);
}
}
}
三、总结
Spring 声明式事务 = AOP 代理 + 模板方法
代理对象拦截 @Transactional 方法 → TransactionInterceptor 按固定 5 步(解析注解→创建/加入事务→执行业务→提交/回滚→清理) → 底层交给 PlatformTransactionManager(JDBC/JTA/Seata)真正做 commit/rollback。
四、学习交流
链接: Java-AI学习交流
一个人的精力是有限的,没有那么多的时间去探索新的事物,加入一个交流群就相当于增加了一个接触新事物、新想法、新机会的渠道,这就是交流群存在的意义,期待你的加入!