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 真的是不容易。 也讓我對不少細節都從新理解了下 其實這些配置都知道 可是沒怎麼好好理解,但願你們能共勉