Spring 循環 事務隔離回滾筆記

note.youdao.com/noteshare?i…測試

實現一個需求 批量進行退款 A中A_1方法查出list,循環list,更新狀態成功後進行打款,打款成功插入打款流水,中途如有失敗回滾當前循環的,以前已打款已更新狀態的數據不進行回顧 即單個回滾ui

僞代碼:this

Class A {spa

method  A_1() {
    List list = dao.selectlist();
    for(obj o: list){
        //處理業務邏輯
        B.B_1();
        dopay();//打款                  
    } }
複製代碼

}代理

B、C、D是封裝好的不能進行修改code

Class B{事務

@Transactional(rollbackFor=Exception.class)
    method B_1(){
            C.C_1();
            D.D_1();
    }
複製代碼

}get

Class C{io

@Transactional(rollbackFor=Exception.class)
    method C_1(){
           update();
    }
複製代碼

}class

Class D{

@Transactional(rollbackFor=Exception.class)
    method D_1(){
           insert();
    }
複製代碼

}

個人腳步: 在A_1上加 @Transactional(rollbackFor=Exception.class) 若要事務回滾須要將終端處的異常一層一層拋出 相似這樣

這樣作的確進行了手動事務回滾的處理,測了一條沒問題,

但是想到,若是多條執行,已經打過錢的訂單,狀態回滾了,那豈不會形成重複打款,

測了4條數據,讓第一條成功打款,第二條拋異常,果真,第一條錢打了,狀態也跟着回滾成未打款狀態,即全部的都回滾了。顯然不是要的結果。

想着把A_1上事務改爲Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor=Exception.class)只知道新建 Transactional(propagation = Propagation.NESTED, rollbackFor=Exception.class)嵌套 具體是什麼並不太瞭解,結果試了後發現都不回滾了,事務不起做用了。這確定也不行。

而後仔細查了下 Spring事務傳播屬性:

1.propagation-required: 支持當前事務,若是有就加入當前事務中;若是當前方法沒有事務,就新建一個事務;
2.propagation-supports: 支持當前事務,若是有就加入當前事務中;若是當前方法沒有事務,就以非事務的方式執行;
3.propagation-mandatory: 支持當前事務,若是有就加入當前事務中;若是當前沒有事務,就拋出異常;
4.propagation-requires_new: 新建事務,若是當前存在事務,就把當前事務掛起;若是當前方法沒有事務,就新建事務;
5.propagation-not-supported: 以非事務方式執行,若是當前方法存在事務就掛起當前事務;若是當前方法不存在事務,就以非事務方式執行;
6.propagation-never: 以非事務方式執行,若是當前方法存在事務就拋出異常;若是當前方法不存在事務,就以非事務方式執行;
7.propagation-nested: 若是當前方法有事務,則在嵌套事務內執行;若是當前方法沒有事務,則與required操做相似;
前六個策略相似於EJB CMT,第七個(PROPAGATION_NESTED)是Spring所提供的一個特殊變量。
它要求事務管理器或者使用JDBC 3.0 Savepoint API提供嵌套事務行爲(如Spring的DataSourceTransactionManager)
複製代碼

想了想,循環外面不能加否則必定會把以前循環執行的更新狀態的所有回滾,應該把循環內容獨立開來,把裏面的處理抽出來,單獨開啓新的事務,因而就這樣寫

Class A {

method  A_1(){
            List list = dao.selectlist();
            for(obj o: list){
               this.dorefund();              
            } 
    }

    Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor=Exception.class)
    method dorefund(){
           //處理業務邏輯
           B.B_1();
           dopay();//打款    
    }
複製代碼

}

在循環體中的抽出單獨放在一個方法裏,進行調用 調用後,fuck 還不行。。。。沒有毛病啊 懷疑人生, 我甚至偷偷把封裝好的裏面的事務所有改爲 Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor=Exception.class),結果仍是不行

後來查了發現是Spring代理的緣由

而後由於和上述的例子有點區別,不能在類上加,用了第1種方法 把dorefund()單獨抽在一個類裏

Class A {

method  A_1(){
    List list = dao.selectlist();
    for(obj o: list){
       E.dorefund();              
        } 
    }
複製代碼

}

Class E{

Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor=Exception.class)
    method dorefund(){
           //處理業務邏輯
           B.B_1();
           dopay();//打款    
    } 
複製代碼

}

測試OK 真的是不容易。 也讓我對不少細節都從新理解了下 其實這些配置都知道 可是沒怎麼好好理解,但願你們能共勉

相關文章
相關標籤/搜索