Spring事務注意事項 以及 遇到的坑

原創參考:html

https://www.cnblogs.com/yougewe/p/7466677.html   (Spring,爲內部方法新起一個事務,此處應有坑。)面試

https://blog.csdn.net/bntx2jsqfehy7/article/details/79040349 (面試必備技能:JDK動態代理給Spring事務埋下的坑!)spring

 

spring 事務注意事項:spa

注意:.net

  @Transactional 能夠做用於接口、接口方法、類以及類方法上。看成用於類上時,該類的全部 public 方法將都具備該類型的事務屬性,同時,咱們也能夠在方法級別使用該標註來覆蓋類級別的定義。代理

  雖然 @Transactional 註解能夠做用於接口、接口方法、類以及類方法上,可是 Spring 建議不要在接口或者接口方法上使用該註解,由於這隻有在使用基於接口的代理時它纔會生效。另外, @Transactional 註解應該只被應用到 public 方法上,這是由 Spring AOP 的本質決定的。若是你在 protected、private 或者默承認見性的方法上使用 @Transactional 註解,這將被忽略,也不會拋出任何異常。日誌

  默認狀況下,只有來自外部的方法調用纔會被AOP代理捕獲,也就是,類內部方法調用本類內部的其餘方法並不會引發事務行爲,即便被調用方法使用@Transactional註解進行修飾。由於動態代理的緣由。code

 

在 SPRING 中一共定義了六種事務傳播屬性

PROPAGATION_REQUIRED -- 支持當前事務,若是當前沒有事務,就新建一個事務。這是最多見的選擇。 
PROPAGATION_SUPPORTS -- 支持當前事務,若是當前沒有事務,就以非事務方式執行。 
PROPAGATION_MANDATORY -- 支持當前事務,若是當前沒有事務,就拋出異常。 
PROPAGATION_REQUIRES_NEW -- 新建事務,若是當前存在事務,把當前事務掛起。 
PROPAGATION_NOT_SUPPORTED -- 以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。 
PROPAGATION_NEVER -- 以非事務方式執行,若是當前存在事務,則拋出異常。 
PROPAGATION_NESTED -- 若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則進行與PROPAGATION_REQUIRED相似的操做。 

最容易弄混淆的實際上是PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 

PROPAGATION_REQUIRES_NEW 啓動一個新的, 不依賴於環境的 "內部" 事務. 這個事務將被徹底 
commited 或 rolled back 而不依賴於外部事務,它擁有本身的隔離範圍, 本身的鎖, 等等. 
當內部事務開始執行時, 外部事務將被掛起, 內務事務結束時, 外部事務將繼續執行. 
PROPAGATION_REQUIRES_NEW經常使用於日誌記錄,或者交易失敗仍須要留痕

另外一方面, PROPAGATION_NESTED 開始一個 "嵌套的" 事務, 它是已經存在事務的一個真正
的子事務. 潛套事務開始執行時, 它將取得一個 savepoint.
若是這個嵌套事務失敗, 咱們將回滾到此 savepoint. 潛套事務是外部事務的一部分,
只有外部事務結束後它纔會被提交. 
因而可知, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大區別在於, 
PROPAGATION_REQUIRES_NEW 徹底是一個新的事務, 而 PROPAGATION_NESTED 
則是外部事務的子事務, 若是外部事務 commit, 潛套事務也會被 commit,
這個規則一樣適用於 roll back. 

幾個例子理解REQUIRED、REQUIRES_NEW、NESTED 的使用注意事項(TRY...CATCH配合使用)

1、REQUIRED的使用注意項

1.1 REQUIRED保證其處理過程同一個事務,若是調用的同一個類的配置的REQUIRED的方法,且此方法存在TRY CATCH
代碼塊, 若是此代碼塊出現異常,程序能夠繼續執行。

1.2 但若是調用的其餘類的配置REQUIRED方法,且TRY CATCH住,則所有的提交所有回滾,且報出異常:
Transaction rolled back because it has been marked as rollback-only
由於事務報出異常後要所有回滾,包括父類的調用。

1.3 若是service中包含多個dao的方法,其都屬於同一個事務,其中報錯所有回滾,try catch住不影響程序代碼的繼續執行.


class A{
//PROPAGATION_REQUIRED
void methodA() {
try{
methodB(); //能夠繼續執行,由於是同一個類
}catch(Exception ex){
ex.printStrace();
}

try{
methodC(); //報錯Transaction rolled back because it has been marked as rollback-only
//由於回滾整個事務,不能用try catch住.固然經過不會try catch一個事務的部分代碼
}catch(Exception ex){
ex.printStrace();
}
}

//PROPAGATION_REQUIRED
void methodB() {

}
}

class B{

//PROPAGATION_REQUIRED
void methodC() {

}
}

2、NESTED的具體用途以下:
在此方法出現異常時,經過TRY CATCH 代碼塊包含住, 繼續往下執行或者執行CATCH中的處理.
此點REUQIRED作不到, REQUIRED_NEW能作到, 但它是單獨的事務,不與父類一塊提交的。

ServiceA { 
/**

* 事務屬性配置爲 PROPAGATION_REQUIRED

*/

void methodA() {

try {

//savepoint

ServiceB.methodB(); //PROPAGATION_NESTED 級別

} catch (SomeException) {

// 執行其餘業務, 如 ServiceC.methodC();
}}}
相關文章
相關標籤/搜索