原創參考: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(); }}}