第6篇-事务资源的绑定与传递
约 1097 字大约 4 分钟
2026-05-24
四、事务同步(TransactionSynchronization)的工作原理
TransactionSynchronization 是 Spring 事务的"回调接口"。它允许你在事务提交/回滚前后执行一些操作。
4.1 TransactionSynchronization 接口
// 类路径:org.springframework.transaction.support.TransactionSynchronization
public interface TransactionSynchronization extends Flushable {
/** 事务提交状态 */
int STATUS_COMMITTED = 0;
/** 事务回滚状态 */
int STATUS_ROLLED_BACK = 1;
/** 事务未知状态(可能是提交或回滚) */
int STATUS_UNKNOWN = 2;
/**
* 挂起时调用。
*
* 当事务被挂起时(比如,遇到 PROPAGATION_REQUIRES_NEW),
* 这个方法会被调用。
*/
default void suspend() {
}
/**
* 恢复时调用。
*
* 当事务被恢复时(比如,PROPAGATION_REQUIRES_NEW 的事务结束后),
* 这个方法会被调用。
*/
default void resume() {
}
/**
* 提交前调用。
*
* @param readOnly 事务是否只读
*/
default void beforeCommit(boolean readOnly) {
}
/**
* 完成前调用(在 commit/rollback 之后)。
*
* @param status 事务状态(提交、回滚、未知)
*/
default void beforeCompletion() {
}
/**
* 提交后调用。
*
* @param status 事务状态(提交、回滚、未知)
*/
default void afterCommit() {
}
/**
* 完成后调用(在 afterCommit 之后)。
*
* @param status 事务状态(提交、回滚、未知)
*/
default void afterCompletion(int status) {
}
}4.2 如何注册事务同步回调?
@Service
public class UserService {
@Transactional
public void createUser(User user) {
// 注册事务同步回调
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void beforeCommit(boolean readOnly) {
System.out.println("事务提交前...");
}
@Override
public void afterCommit() {
System.out.println("事务提交后...");
// 可以在这里发送消息、清理缓存等
}
@Override
public void afterCompletion(int status) {
System.out.println("事务完成后,状态:" + (status == STATUS_COMMITTED ? "已提交" : "已回滚"));
}
});
userMapper.insert(user);
}
}4.3 Spring 是如何触发这些回调的?
在 AbstractPlatformTransactionManager 的 processCommit() 和 processRollback() 方法中:
// 类路径:org.springframework.transaction.support.AbstractPlatformTransactionManager
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
/**
* 处理事务提交。
*/
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
// 1. 触发 beforeCommit 回调
triggerBeforeCommit(status);
// 2. 触发 beforeCompletion 回调
triggerBeforeCompletion(status);
// 3. 执行提交
doCommit(status);
// 4. 触发 afterCommit 回调
triggerAfterCommit(status);
}
finally {
// 5. 触发 afterCompletion 回调
triggerAfterCompletion(status);
}
}
/**
* 触发 beforeCommit 回调。
*/
private void triggerBeforeCommit(DefaultTransactionStatus status) {
if (status.isNewSynchronization()) {
if (status.isReadOnly()) {
TransactionSynchronizationManager.triggerReadOnlyStatus();
}
TransactionSynchronizationUtils.triggerBeforeCommit(status);
}
}
/**
* 触发 afterCommit 回调。
*/
private void triggerAfterCommit(DefaultTransactionStatus status) {
if (status.isNewSynchronization()) {
TransactionSynchronizationUtils.triggerAfterCommit(status);
}
}
}五、扩展点总结
在这篇文章中,我们提到了以下几个扩展点:
| 扩展点 | 场景 | 如何扩展 |
|---|---|---|
| 自定义事务同步回调 | 你想在事务提交/回滚前后执行一些操作(比如,清理缓存、发送消息) | 实现 TransactionSynchronization 接口,并注册到 TransactionSynchronizationManager |
| 多数据源支持 | 你有多个数据库,想用不同的事务管理器 | 配置多个 PlatformTransactionManager Bean,并使用 @Transactional(transactionManager = "...") 指定 |
| 自定义资源管理 | 你想管理其他资源(比如,Redis 连接) | 继承 AbstractPlatformTransactionManager,重写 doBegin()、doCommit()、doRollback() 等方法 |
六、小结与伏笔
好了,到这里,我们已经把事务资源"绑定与传递"的神秘面纱揭开了。
让我们来回顾一下整个流程:
- 当调用一个事务方法时,
TransactionInterceptor.invoke()会被调用 invoke()方法调用了TransactionAspectSupport.invokeWithinTransaction()方法invokeWithinTransaction()方法调用了createTransactionIfNecessary()方法createTransactionIfNecessary()方法调用了getTransaction()方法getTransaction()方法调用了doBegin()方法(如果新建事务)doBegin()方法会:获取连接、设置隔离级别、关闭自动提交、绑定连接到当前线程- 当 MyBatis 执行 SQL 时,会调用
DataSourceUtils.getConnection() getConnection()方法会调用TransactionSynchronizationManager.getResource()getResource()方法会从当前线程的 ThreadLocal 中获取ConnectionHolder- 从
ConnectionHolder中获取Connection,并使用这个连接执行 SQL
🔮 伏笔:Spring 事务与 MyBatis 是如何集成的?
你可能会注意到,MyBatis 需要使用 Spring 管理的事务连接。
那么问题来了:
- MyBatis 的
SqlSession是如何与 Spring 的事务集成的? - MyBatis 的一级缓存与 Spring 事务有什么关系?
- 如果 MyBatis 执行的 SQL 抛出异常,Spring 事务是如何回滚的?
这些问题,我们会在系列三(MyBatis 系列)中详细讲解。
下一篇预告:《Spring 事务(七):提交、回滚与异常规则》
在这篇文章中,我们会讲解:
commit()和rollback()的源码实现- 异常回滚规则的匹配逻辑
UnexpectedRollbackException和RollbackOnly的原理- 事务提交/回滚时的同步回调触发时机
写在最后:这篇文章比较长,但我觉得值得。因为只有当理解了事务资源的"绑定与传递"机制,你才能真正理解 Spring 事务是如何与 MyBatis、JPA 等 ORM 框架集成的。如果你有什么疑问,欢迎留言讨论!