关于TransactionSynchronizationManager的使用事务问题

背景

      相信很多小伙伴在工作中,都遇到过想在这个业务方法执行后,且事务提交成功了,我在去查询XXX,或者业务之类的。  但是你现在已经有的公共抽象方法 不敢轻易乱动。

这个时候你可以用spring预留的口子去执行对应的业务方法, 很多人不清楚这之间的事务关系,我已经给你们整理好啦~

 

 

一 、syncToRedis 异步

1、异步 afterCommit 是否能查到提交后的值?

我们把syncToRedis 进行异步处理,看看 A业务进行更新,然后syncToRedis同步操作里面是否获取到最新的值。

@Transactional 
public void test(){
   // 把“Y”更新成"N"
   updateToN();
 
   TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// 每天更新完,就插入到redis里面去
syncToRedis();
}
});
   
   
}

@Async
public void  syncToRedis(){
   select();
}

 

结果: syncToRedis虽然是异步的,但是我们也等到事务结束之后select()到了最新的值为N。

下面我们测试 代码异常情况。先把刚才更新为N的恢复为Y状态。

 

2、异步afterCommit之异常情况下test()是否回滚

 

我们这次把异常先放到主体代码中也就是test();

@Transactional 
public void test(){
   // 把“Y”更新成"N"
   updateToN();
 
   TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// 每天更新完,就插入到redis里面去
syncToRedis();
}
});
   
   // 测试异常
   throw  new  NullPointerException();
}

@Async
public void  syncToRedis(){
   select();
}

 

结果:

查看堆栈,报了空指针异常 stack_trace":"java.lang.NullPointerException

再看数据库: 发现的确没有被更新为"N"; 证明这个的确是在事务提交之后才执行的。

 

3、异步afterCommit之异常在afterCommit()是否回滚

 

@Transactional 
public void test(){
   // 把“Y”更新成"N"
   updateToN();
 
   TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// 每天更新完,就插入到redis里面去
syncToRedis();
               // 测试异常
                throw  new  NullPointerException();
}
});
   
   
}

@Async
public void  syncToRedis(){
   select();
 
}

结果:

查看堆栈,报了空指针异常 stack_trace":"java.lang.NullPointerException

在查看数据库, 全部更新为"N"了, 那么可以得出, 如果你在afterCommit()方法中抛出异常,那是不会让test()方法回滚的。

 

4、异步afterCommit之异常在syncToRedis()

 

@Transactional 
public void test(){
   // 把“Y”更新成"N"
   updateToN();
 
   TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// 每天更新完,就插入到redis里面去
syncToRedis();
}
});
   

 
}

@Async
public void  syncToRedis(){
   select();
     // 测试异常
   throw  new  NullPointerException();
}

结果:

查看堆栈,报了空指针异常 stack_trace":"java.lang.NullPointerException

在查看数据库, 全部更新为"N"了, 那么可以得出, 如果你在syncToRedis()方法中抛出异常,那是不会让test()方法回滚的。

 

 

5、异步afterCommit之异常在afterCommit()且UpdateToC

 

@Transactional 
public void test(){
   // 把“Y”更新成"N"
   updateToN();
 
   TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// 每天更新完,就插入到redis里面去
syncToRedis();
               // 测试异常
  throw  new  NullPointerException();
}
});
   
   // 更新为C
    updateToC();
}

@Async
public void  syncToRedis(){
   select();
 
}

结果:

查看堆栈,报了空指针异常 stack_trace":"java.lang.NullPointerException

在查看数据库, 全部更新为"C"了, 那么可以得出,一定是执行Test()事务,才会执行afterCommit(), 如果你在afterCommit()方法中抛出异常,那是不会让test()方法回滚的。

 

 

 

总结:

前提条件:test()带@Transactional ,且syncToRedis()为async

①test()方法一定是先执行完,才会去执行afterCommit()方法。

②test()方法异常, test方法回滚,且不执行afterCommit()方法。

③ afterCommit()方法内任何方法异常,test()方法不回滚,不影响test()业务。

 

二、syncToRedis同步带事务

前提条件:test()带@Transactional ,且syncToRedis带@Transactional

直接说总结把:

①test()方法一定是先执行完,才会去执行afterCommit()方法。 同上面

②test()方法异常, test方法回滚,且不执行afterCommit()方法。同上面

③ afterCommit()方法内任何方法异常,test()方法不回滚,不影响test()业务。 同上面

 

所以你的同步和异步是完全没有任何区别的。

 

 

 

 

posted @ 2021-09-30 12:03  Rick_Leee  阅读(3667)  评论(0编辑  收藏  举报