在循環中處理事務


問題闡述及解決過程

現在需要寫一個定時任務,其處理過程要在for循環進行,並且循環體中要調用兩個方法,大致代碼是這樣的:

 1 public void regionRecoveryProtectionPeriod() {
 2         for (????) {
 3             try {
 4                 method1();
 5                 method2();
 6             } catch (Exception e){
 7                 log.error("",e.getMessage());
 8             }
 9         }
10 }

用try將循環體包裹起來防止循環中斷,但是這段存在一個問題——循環體中沒有用事務管理,這將會造成很嚴重的后果。

 

很容易想到的方法就是將循環體單獨寫到一個方法里,將這個新的方法上加事務,代碼如下:

 1 public void regionRecoveryProtectionPeriod() {
 2         for (????) {
 3             try {
 4                 this.releaseOrigin();
 5             } catch (Exception e){
 6                 log.error("",e.getMessage());
 7             }
 8         }
 9 
10 @Transactional(rollbackFor = Exception.class)
11  void releaseOrigin() {
12         method1();
13         method2();
14     }

這段代碼看似沒有問題,但是經過試驗,發現事務並沒有起作用,和原來的結果沒有任何區別。

 

原因是自調用不走代理對象,所以用this.調用內層方法時注解是不生效的,因此要通過代理對象的方式調用內層方法:Object proxy = AopContext.currentProxy();

代碼如下:

public void regionRecoveryProtectionPeriod() {
        Service proxy = (Service)AopContext.currentProxy();
        for (????) {
            try {
                proxy.releaseOrigin();
            } catch (Exception e){
                log.error("",e.getMessage());
            }
        }

@Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
 void releaseOrigin() {
        method1();
        method2();
    }

這樣做的話,內部事務就能正常生效了,由於外層的方法通常也是要加事務的,所以內層的事務要加上propagation = Propagation.NESTED讓內層事務不會影響到外層事務。

 

總結

關於這種問題的解決方案有人說可以將內層事務的方法寫在別的service里,或者自己注入自己。代理對象的方法里用了ThreadLocal里的get方法,不知道是否會對性能有啥影響。如果有更好的方法的話可以交流一下

 


免責聲明!

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



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