標籤:nal tac 調用 thread create 提交 系統 llb 失敗
提起spring事務,就會讓人聯想起四大基本特徵,五個隔離等級,七大傳播特性。相信大多數人都知道這些東西,但是知道是一回事情,能用好真的是另一回事了。在使用Spring事務的時候,我曾遇到過幾個比較嚴肅的問題,在這裡我做一個自我總結。 問題一、 propagation.NESTED和propagation.REQUIRED_NEW有什麼區別?
當調用方不存在事務的時候,兩者的效果是一致的。所以這裡討論問題的前提是調用方存在事務。PROPAGATION_REQUIRES_NEW 啟動一個新的, 不依賴於環境的 "內部" 事務. 這個事務將被完全 commited 或 rolled back 而不依賴於外部事務, 它擁有自己的隔離範圍, 自己的鎖, 等等. 當內部事務開始執行時, 外部事務將被掛起, 內務事務結束時, 外部事務將繼續執行.
另一方面, PROPAGATION_NESTED 開始一個 "嵌套的" 事務, 它是已經存在事務的一個真正的子事務. 潛套事務開始執行時, 它將取得一個 savepoint. 如果這個嵌套事務失敗, 我們將復原到此 savepoint. 潛套事務是外部事務的一部分, 只有外部事務結束後它才會被提交.
由此可見, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大區別在於, PROPAGATION_REQUIRES_NEW 完全是一個新的事務, 而 PROPAGATION_NESTED 則是外部事務的子事務, 如果外部事務 commit, 潛套事務也會被 commit, 這個規則同樣適用於 roll back.
問題二、 @Transactional為什麼會失效?
1.調用方和被呼叫者屬於同一個component,被呼叫者的 @Transacational 註解無效
package com.transacational;import org.springframework.stereotype.Component;import org.springframework.transaction.annotation.Transactional;/** * Created by chenqimiao on 17/10/31. */@Componentpublic class Service { public void test1(){ test2(); } @Transactional//此處的註解無效 public void test2(){ }}
2.被呼叫者不是一個public方法,被呼叫者的 @Transacational 註解無效
@Componentpublic class Service { @Resource private Service1 service1; public void test1(){ test2(); service1.test3(); } @Transactional//1.此處的註解無效 public void test2(){ }}
package com.transacational;import org.springframework.stereotype.Component;import org.springframework.transaction.annotation.Transactional;/** * Created by chenqimiao on 17/10/31. */@Componentpublic class Service1 { @Transactional//2.此處註解無效 protected void test3(){ }}
3.未開啟事務開關,如:在SpringBoot中,啟動類未使用 @EnableTransactionManagement
問題三、 如何理解@Transactional的逾時時間?
timeout 是一個供開發人員設定逾時時間的屬性。預設值-1,逾時時間由具體的sql系統決定。
/** * Created by chenqimiao on 17/10/31. */@Componentpublic class Service3 { @Resource private AdminInfoDoMapper adminInfoDoMapper; @Transactional(timeout = 4)//並不會逾時 public void test4(){ adminInfoDoMapper.selectNameById(1); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } }}
逾時時間具體的定義:事務開始(在該方法第一句代碼執行之前)到最後一個Statement執行完畢
所以象下面這樣寫,事務就會逾時
@Componentpublic class Service3 { @Resource private AdminInfoDoMapper adminInfoDoMapper; @Transactional(timeout = 4) public void test4(){ try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } adminInfoDoMapper.selectNameById(1); }}
問題四、 @Transactional預設的復原策略?
預設情況下,只有當RuntimeException或其子類的異常被事務捕獲之後,事務才會復原,如果要讓事務能夠復原所有異常,必須手動指定 @Transactional(rollbackFor=Exception.class) ,這樣繼承Exception的子類或者Exception本身都可以讓交易回復。
對Spring事務的一些誤解