文章
问答
冒泡
利用TransactionSynchronizationManager实现对事务的控制
在使用注解事务的时候,我们需要在事务提交之后,执行某个操作。
例如,我们需要保存某个数据之后,通过MQ去异步处理消息,如果直接在事务内写的话,如果MQ无积压,处理速度比较快的话,可能会在事务提交之前,就已经请求处理了。这个时候,由于mysql事务未提交,读取到数据,是之前的数据,也就是说,如果是新增了一条数据,这个时候来处理,是处理不到的。那么我们有没有办法确保事务提交之后,再去发送这个消息呢?
  1. 把发送消息的代码写在事务外面
  2. 编程式事务
  3. 利用TransactionSynchronizationManager实现对事务的控制
如果把代码写在事务外面,那么就意味着,事务的方法和发送消息的方法不能写在同一个class下了,spring的注解事务是基于aop的这个情况大家都知道。如果用编程式事务,还得自己去提交什么的。出于代码的可读性和偷懒的原则,我们选择用TransactionSynchronizationManager。
 
我们写一段代码测试下
@Transactional
public void submit(QuestionDraft questionDraft) {
    ......
    questionDraftManager.save(questionDraft);
    log.info("----------transaction uncommitted--------");
    //region 事务提交之后发生mq消息
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
        @Override
        public void afterCompletion(int status) {
            log.info("-----------transaction committed-------");
            if(Objects.equals(0,status)){
                log.info("提交到MQ进入审核队列");
            }
        }
    });
    //endregion
}
 
日志级别设置为debug看看日志,可以看到,这个日志是在事务提交之后才执行的。
 
那么,这个TransactionSynchronizationManager 是怎么做到呢?我们看下源码。
 
可以看到,这里是将这些TransactionSynchronization注册到当前的ThreadLocal上,那么注册上去之后又是怎么使用的呢?我们根据类的引用找到了TransactionSynchronizationUtils,可以看到里面会去遍历触发相关的函数。
顺着TransactionSynchronizationUtils 网上找,在AbstractPlatformTransactionManager 这个抽象类中找到了这样的一段
这就清晰了,顺着调用可以看到这些方法最终会被事务管理器调用。
 
很多资料上在事务执行之后,是使用的afterCommit ,其实要看自己的需求,afterCommit 只是事务提交了,但是提交的结果还没有得到,比较保险的是用afterCompletion,可以根据事务提交的结果来执行自己的逻辑。

spring
transaction

关于作者

落雁沙
非典型码农
获得点赞
文章被阅读