TransactionSynchronizationManager.registerSynchronization 是 Spring 框架中用于 动态注册事务生命周期回调钩子(Hook)的静态核心方法。
它允许开发者在当前线程的事务执行到特定阶段(如:提交前、提交后、回滚后)时,自动触发自定义的业务逻辑。
最常用于事务提交后发送 MQ 消息、清理缓存或发送邮件,以确保这些外围操作只有在数据库事务成功后才执行。
假设在注册用户成功(数据库插入成功)后,需要发送一条 MQ 消息或者是给用户发送邮件。如果直接写在 @Transactional 方法内,一旦后续代码抛出异常导致事务回滚,MQ 消息或邮件却已经发出去了,就会导致数据不一致。
关键生命周期钩子(常用方法)
1、beforeCommit(boolean readOnly): 在事务提交前触发,此时仍在当前事务内。
2、beforeCompletion(): 在事务提交或回滚前触发,用于做最后的资源清理。
3、afterCommit(): (最常用) 事务成功提交后触发,适合做写缓存、发短信邮件等不可逆的外围操作
4、afterCompletion(int status): 事务完成后触发(无论提交还是回滚均会调用)。可以通过入参判断状态
注意事项
1、必须在现有的事务范围内调用
如果在没有 @Transactional 或没有开启事务的线程中直接调用 registerSynchronization,系统就会抛出 IllegalStateException: Transaction synchronization is not active 异常
解决:调用前使用 TransactionSynchronizationManager.isSynchronizationActive() 先判断一下。
2、afterCommit 中不能再执行数据库写操作
当执行到 afterCommit() 时,底层的数据库连接一般是已经完成提交并可能被释放或关闭了。如果在执行带 @Transactional 的数据库保存方法,会引发异常,或者报错连接已关闭
3、需要注意线程隔离
TransactionSynchronizationManager 的底层基于 ThreadLocal 实现。回调逻辑必须与开启事务的代码在同一个线程中运行。如果在这个事务方法中,开了一个新线程,则在子线程内调用 TransactionSynchronizationManager.registerSynchronization 是不会被主线程触发的。
4、afterCommit 阻塞会拖垮数据库连接池
虽然 afterCommit 是在提交之后执行,但在整个回调彻底执行完之前,当前线程持有的数据库连接是不会被释放掉的。如果回调逻辑里面有特别耗时间的 RPC 请求、HTTP同步调用、甚至是死循环,这样会导致数据库的连接池被迅速耗尽,会导致怎样的结果不言而喻。
解决:直接把这个回调扔进自定义线程池异步处理就行
代码示例(AI生成)
方案一:兼容方案(基于硬编码 TransactionSynchronization)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@Service
public class OrderService {
private static final Logger log = LoggerFactory.getLogger(OrderService.class);
@Transactional(rollbackFor = Exception.class)
public void createOrderWithSync(Order order) {
// 1. 执行核心数据库操作
orderDao.save(order);
log.info("【业务】订单落库成功,订单号: {}", order.getId());
// 2. 安全校验:必须确保当前存在激活的 Spring 事务环境,否则注册会抛出 IllegalStateException
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 3. 动态注册事务同步回调
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void beforeCommit(boolean readOnly) {
// 触发时机:数据库连接的 commit() 即将调用前。此时仍在当前事务内。
// 避坑:可以进行最后的校验或数据准备,但不要在这里做耗时过长的操作。
log.info("【钩子-beforeCommit】事务准备提交,是否只读事务: {}", readOnly);
}
@Override
public void afterCommit() {
// 触发时机:数据库物理 commit 成功之后。
// 典型场景:发送 MQ 消息、清除 Redis 缓存、发送通知短信。
// 避坑:此时数据库连接尚未归还连接池,严禁在此处执行耗时超长的 RPC 或 HTTP 同步调用!
log.info("【钩子-afterCommit】事务已成功提交!开始执行外围非事务逻辑(如发送 MQ,更新缓存)");
// 建议:耗时任务应异步化,防止阻塞数据库连接归还
// executor.execute(() -> mqService.sendOrderMessage(order));
}
@Override
public void afterCompletion(int status) {
// 触发时机:整个事务链路彻底结束(无论成功提交还是回滚都会执行)。
// 常用作:ThreadLocal 的清理、临时文件的删除、监控埋点。
if (status == TransactionSynchronization.STATUS_COMMITTED) {
log.info("【钩子-afterCompletion】事务流程最终状态:[成功提交]");
} else if (status == TransactionSynchronization.STATUS_ROLLED_BACK) {
// 典型场景:在这里触发业务层面的补偿机制,或者记录异常回滚日志
log.warn("【钩子-afterCompletion】事务流程最终状态:[发生回滚],开始清理临时数据...");
}
}
});
} else {
// 如果没有事务环境,则直接走兜底的普通同步/异步业务逻辑
log.warn("【警告】当前无激活事务环境,直接触发外围逻辑");
}
}
}方案二:Spring 4.2+ 方案(基于 Spring Event + 声明式注解)
此方案推荐用于 Spring 4.2+ 之后的项目。它通过应用事件(ApplicationEvent)解耦业务骨架与外围钩子,代码中完全看不到侵入式的事务管理器代码。
1.、定义事件载体(POJO 类)
public class OrderCreatedEvent {
private final Order order;
public OrderCreatedEvent(Order order) {
this.order = order;
}
public Order getOrder() {
return order;
}
}2、核心业务类(发布事件)
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class ModernOrderService {
private final ApplicationEventPublisher eventPublisher;
private final OrderDao orderDao;
public ModernOrderService(ApplicationEventPublisher eventPublisher, OrderDao orderDao) {
this.eventPublisher = eventPublisher;
this.orderDao = orderDao;
}
@Transactional(rollbackFor = Exception.class)
public void createOrder(Order order) {
// 1. 核心数据库操作
orderDao.save(order);
// 2. 只负责发布事件,不再关心事务何时提交,彻底实现业务解耦
// 注意:事件发布本身是同步的,但监听器的执行时机受控制
eventPublisher.publishEvent(new OrderCreatedEvent(order));
}
}3. 事件监听类(声明式钩子)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
@Component
public class OrderTransactionListener {
private static final Logger log = LoggerFactory.getLogger(OrderTransactionListener.class);
/**
* 场景一:对应 beforeCommit
*/
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void onBeforeCommit(OrderCreatedEvent event) {
log.info("【BEFORE_COMMIT】收到事件,事务即将提交。订单号: {}", event.getOrder().getId());
}
/**
* 场景二:对应 afterCommit (如果不写 phase 属性,默认就是 AFTER_COMMIT)
*/
@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void onAfterCommit(OrderCreatedEvent event) {
log.info("【AFTER_COMMIT】数据库事务已确认提交!安全处理外围逻辑");
}
@Async
@TransactionalEventListener(
phase = TransactionPhase.AFTER_COMMIT,
fallbackExecution = true // 如果当前没有事务,立刻执行该逻辑(兜底)
)
public void onAfterCommit(OrderCreatedEvent event) {
log.info("【AFTER_COMMIT】执行外围逻辑");
}
/**
* 场景三:对应 afterCompletion 中的回滚状态
*/
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void onAfterRollback(OrderCreatedEvent event) {
log.warn("【AFTER_ROLLBACK】捕获到数据库事务回滚!执行异常补偿机制...");
}
/**
* 场景四:对应 afterCompletion (无论提交或回滚均触发)
*/
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
public void onAfterCompletion(OrderCreatedEvent event) {
log.info("【AFTER_COMPLETION】事务链路结束,进行日志收尾。");
}
}
微信扫码查看本文
发表评论