本篇主要討論下面幾點獲取【下載地址】 :
一: Spring 事務的傳遞性介紹
二: 第三方調用含有事務的Service拋異常方法探討
一: Spring 事務的傳遞性介紹
事務傳播行為,所謂事務的傳播行為是指,如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行為。在TransactionDefinition定義中包括了如下幾個表示傳播行為的常量:
TransactionDefinition.PROPAGATION_REQUIRED:如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:創建一個新的事務,如果當前存在事務,則把當前事務掛起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務方式運行,如果當前存在事務,則把當前事務掛起。
TransactionDefinition.PROPAGATION_NEVER:以非事務方式運行,如果當前存在事務,則拋出異常。
TransactionDefinition.PROPAGATION_MANDATORY:如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。
TransactionDefinition.PROPAGATION_NESTED:如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價TransactionDefinition.PROPAGATION_REQUIRED。
這裡需要指出的是,前面的六種事務傳播行為是 Spring 從 EJB 中引入的,他們共享相同的概念。而 PROPAGATION_NESTED是 Spring 所特有的。以 PROPAGATION_NESTED 啟動的事務內嵌於外部事務中(如果存在外部事務的話),此時,內嵌事務並不是一個獨立的事務,它依賴於外部事務的存在,只有通過外部的事務提交,才能引起內部事務的提交,嵌套的子事務不能單獨提交。如果熟悉 JDBC 中的保存點(SavePoint)的概念,那嵌套事務就很容易理解了,其實嵌套的子事務就是保存點的一個應用,一個事務中可以包括多個保存點,每一個嵌套子事務。另外,外部事務的回滾也會導致嵌套子事務的回滾。
二: 第三方調用含有事務的Service拋異常方法探討
假設術語如下:調用方Conumer, 調用Service的methodA, methodA調用Service的 methodB
a)methodA 傳播屬性為required, methodB傳播屬性為required, 代碼如下
Java代碼
發現Consumer調用MethodA的時候出現了運行時異常,UnexpectedRollbackException: “Transaction rolled back because it has been marked as rollback-only”。這是為什麼呢?
網上搜索了下,終於發現了一個合理的解釋。當MethodA調用MethodB的時候,且兩個方法都為required屬性,則methodA和methodB共享一個事務,當methodB拋出了異常,則共享事務回滾,但是被MethodA catch了,而MethodA又沒有及時拋出異常,則MethodA正常執行到最後的時候,則會做提交事務的操作,但是事務已經被回滾了,所以才出現了上面的異常。
既然這樣,小弟就開始YY了一下,哪些情況會使調用方沒有這個異常呢?經過與小伙伴們的思維碰撞,發現有一下幾個方法。
b) MethodA 不加事務,所以執行到最後就不會commit,SUPPORTS和NOT_SUPPORTED都可以實現這種功能。
c) MethodB 設置不共享事務,擁有自己單獨的事務。驗證發現,REQUIRES_NEW可以實現這種功能。
然後又YY了下,既然一個回滾的事務不能提交了,那麼這個回滾的事務可以重復回滾嗎?
d) MethodA 調用MethodB,如果MethodA不catch MethodB,則調用方會怎麼樣?很簡單當然直接捕獲到MethodB的異常了,但是感覺這個場景不能完全反應初回滾的事務是否可以重復回滾。代碼如下:
Java代碼
e) 還有什麼場景可以模擬回滾的事務是否可以再回滾呢?看,代碼如下:
Java代碼
第一個MethodB已經回滾了共享的事務,第二個MethodB同樣會拋出異常回滾共享的事務,如果執行了後面的System.out,則說明事務可以多次回滾。測試發現打印出來了後面的SysOut的內容,所以猜測可能是這樣回滾事務的時候如果發現事務已經回滾,則直接跳過。