好。Spring 事务的三大核心接口是整个事务体系的"骨架"------@Transactional 注解背后跑的就是这三个。理解了它们,编程式事务、多数据源、自定义事务行为这些高级用法就都通了。我用"餐厅点餐"比喻把三个接口串起来,再讲实战。
先理解三个接口的角色分工
把事务操作想象成"在餐厅点一道菜",三个接口各管一段:
- TransactionDefinition = 你下的订单(要几分熟、加不加辣、打包还是堂食------你想要这单事务"长什么样")。
- PlatformTransactionManager = 厨师(按订单执行:下锅、出锅、上菜,或者菜做坏了撤销重做)。
- TransactionStatus = 这道菜当前的状态(已下锅没、上桌没、退回没------这一单事务运行到哪了)。
调用链是这样的:你拿出一份 TransactionDefinition(订单)→ 交给 PlatformTransactionManager(厨师)→ 厨师返回一个 TransactionStatus(订单号 + 状态)→ 你执行业务代码 → 厨师根据状态 commit() 或 rollback()。
这就是编程式事务最底层的调用方式。
一、TransactionDefinition:定义"事务要长什么样"
它是一个接口,定义了事务的四个属性 + 一个名字:
java
public interface TransactionDefinition {
int getPropagationBehavior(); // 传播行为(7 种)
int getIsolationLevel(); // 隔离级别(5 种)
int getTimeout(); // 超时秒数(默认 -1 不超时)
boolean isReadOnly(); // 是否只读
String getName(); // 事务名(用于监控/日志)
}
最常用实现是 DefaultTransactionDefinition------一个简单的 POJO 实现,new 出来 set 属性就行:
java
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
def.setTimeout(30);
def.setReadOnly(false);
@Transactional 注解的本质就是把注解属性封装成一个 TransactionDefinition(具体是 RuleBasedTransactionAttribute,多了回滚规则)传给事务管理器。
这个接口能干什么 :在运行时动态构造事务属性 。比如"根据业务类型决定要不要开新事务、超时多久"------注解是静态的,DefaultTransactionDefinition 可以运行时拼。
二、PlatformTransactionManager:执行事务的核心
它是"事务的执行者",接口只有三个方法,却支撑了所有 Spring 事务能力:
java
public interface PlatformTransactionManager {
// 开启新事务 或 加入已有事务(按传播行为决定)
TransactionStatus getTransaction(@Nullable TransactionDefinition definition);
// 提交(注意:如果 status 被标记为 rollbackOnly,仍会回滚)
void commit(TransactionStatus status);
// 回滚
void rollback(TransactionStatus status);
}
getTransaction 是关键 ------它不是单纯"开启",而是按 TransactionDefinition 的传播行为决定:开新的、加入当前的、挂起当前的、抛异常......7 种传播机制全部在这里实现。
Spring 为不同持久层提供了不同实现:
| 实现类 | 适用场景 |
|---|---|
DataSourceTransactionManager |
JDBC / MyBatis / MyBatis-Plus |
JpaTransactionManager |
JPA / Hibernate |
HibernateTransactionManager |
老 Hibernate(非 JPA) |
JtaTransactionManager |
分布式事务(JTA/XA) |
CciTransactionManager |
JCA CCI(很少用) |
Spring Boot 自动按 classpath 里的依赖选一个注入容器。比如你引了 spring-boot-starter-jdbc,自动注入 DataSourceTransactionManager。
这个接口能干什么:
- 手动控制事务(编程式事务),不用注解也能开/提交/回滚;
- 多数据源各自配一个事务管理器 ,用
@Transactional(transactionManager = "xxx")切换; - 自定义事务管理器(比如接 Seata、接自研分布式事务框架),实现接口包一层即可;
- 测试里手动控制事务 (比如
@Transactional+rollback测试数据隔离)。
三、TransactionStatus:当前事务的运行态
它代表"这一单事务的实时状态",由 getTransaction() 返回。核心方法:
java
public interface TransactionStatus extends SavepointManager, Flushable {
boolean isNewTransaction(); // 是不是新开的事务(而非加入已有)
boolean hasSavepoint(); // 是否持有 savepoint(嵌套事务)
void setRollbackOnly(); // 标记"只回滚"------后面即使 commit 也回滚
boolean isRollbackOnly(); // 是否被标记回滚
boolean isCompleted(); // 是否已结束(commit 或 rollback 之后)
// 继承自 SavepointManager
Object createSavepoint(); // 创建 savepoint
void rollbackToSavepoint(Object savepoint); // 回滚到 savepoint
void releaseSavepoint(Object savepoint); // 释放 savepoint
}
最有用的方法是 setRollbackOnly() ------它在业务代码里"标记这单事务必须回滚",但不立刻抛异常,等外层方法正常返回时事务管理器发现这个标记,自动回滚。这是嵌套调用里"内层失败但不想抛异常影响外层流程"的常用招。
这个接口能干什么:
- 判断当前是新事务还是加入的(决定要不要自己提交);
- 标记回滚但不抛异常(流程控制);
- 手动操作 savepoint 实现自定义嵌套逻辑;
- 监控事务进度(是否已完成、是否回滚)。
三者怎么配合干活------编程式事务典型代码
java
@Autowired
private PlatformTransactionManager txManager;
public void doBusiness() {
// 1. 定义订单
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
def.setTimeout(10);
// 2. 厨师按订单下锅,返回订单状态
TransactionStatus status = txManager.getTransaction(def);
try {
// 3. 执行业务
accountDao.debit(...);
accountDao.credit(...);
// 也可以中途标记回滚(不抛异常)
// status.setRollbackOnly();
// 4. 成功提交
txManager.commit(status);
} catch (Exception e) {
// 5. 失败回滚
txManager.rollback(status);
throw e;
}
}
这就是 @Transactional 注解背后跑的代码。注解只是语法糖,把上面这套模板用 AOP 包起来。
真实战用:我们能用三大接口做什么
下面是实战场景,按生产使用频率排:
1. 编程式精确控制事务范围(避免长事务)
@Transactional 是方法级,整个方法都在事务里------但方法里只有 3 行是关键操作,其他是计算、RPC、日志。用 PlatformTransactionManager 只包关键 3 行,事务短得多,连接和锁持有时间大幅下降。生产环境长事务克星。
2. 多数据源各自独立事务管理
多数据源场景下,给每个数据源配一个 DataSourceTransactionManager,方法上用 @Transactional(transactionManager = "orderTxManager") 指定走哪个。配合 @Primary 标注默认事务管理器。
3. 嵌套事务精确控制(savepoint)
用 TransactionStatus.createSavepoint() 手动创建保存点,失败时 rollbackToSavepoint() 只回滚到保存点、不影响外层。比 NESTED 传播更细粒度------可以一段代码里建多个保存点,逐段回滚。
4. 标记回滚但不中断流程
业务异常不想抛出去影响外层,但想让事务回滚------status.setRollbackOnly() 完美胜任。典型场景:调用第三方服务失败,记失败日志、返回降级值,但事务必须回滚保证数据一致。
5. 自定义事务管理器接分布式事务框架
实现 PlatformTransactionManager,把 getTransaction/commit/rollback 桥接到 Seata、DTF、自研的分布式事务协调器。上层 @Transactional 代码完全不用改,框架透明接入。
6. 事务回调监听(TransactionSynchronization)
通过 TransactionSynchronizationManager.registerSynchronization(...) 注册回调------afterCommit(提交后)、afterCompletion(结束后)等。能在事务真正提交后 才发 MQ、才清缓存、才调外部 API,避免"事务还没提交,消息已发出"导致下游读到脏数据的不一致问题。这是生产里解决"事务+MQ"一致性的标准招。
7. 测试数据隔离
测试方法加 @Transactional,测试结束 Spring 自动 rollback------测试数据不污染数据库。底层就是 PlatformTransactionManager 在测试结束时调 rollback。
8. 事务超时动态控制
DefaultTransactionDefinition.setTimeout(30),每个事务按业务动态设置超时------重要接口 30 秒、批量任务 300 秒、查询 5 秒。@Transactional(timeout = 30) 是静态的,编程式更灵活。
一个常被忽略的认知点
很多人觉得"我用 @Transactional 注解就够了,干嘛学这些接口"。事实是------@Transactional 的所有行为,最终都是这三个接口在背后跑。理解它们,能:
- 看懂 Spring 事务源码、出问题能调试;
- 在注解搞不定的场景(动态属性、精确范围、多数据源、自定义回滚逻辑)有退路;
- 自研框架、改造中间件时知道从哪儿切入。
一句话总结------TransactionDefinition 告诉"事务该怎么做",PlatformTransactionManager 是"做事的人",TransactionStatus 是"做完一阶段的状态报告"。三者组合 = Spring 事务的完整执行模型,注解只是这套模型的最薄一层包装。