關於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()業務。 同上面

 

所以你的同步和異步是完全沒有任何區別的。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM