在實際項目中爲了保證數據的一致性,事務是非常重要的,而spring對事務的支持方便了我們對事務相關操作的開發.
事務的配置方式
spring支持編程式事務管理和聲明式事務管理兩種方式。
編程式事務管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。對於編程式事務管理,spring推薦使用TransactionTemplate。
聲明式事務管理建立在AOP之上的。其本質是對方法前後進行攔截,然後在目標方法開始之前創建或者加入一個事務,在執行完目標方法之後根據執行情況提交或者回滾事務。
聲明式事務管理也有兩種常用的方式,一種是基於tx和aop名字空間的xml配置文件,另一種就是基於@Transactional註解。顯然基於註解的方式更簡單易用,更清爽。
事務傳播機制
名稱 | 作用 |
|
|
|
|
|
新建事務,如果當前存在事務,則把當前事務掛起 這個方法會獨立提交事務,不受調用者的事務影響,父級異常,它也是正常提交 |
|
該傳播機制不支持事務,如果外層存在事務則掛起,執行完當前代碼,則恢復外層事務,無論是否異常都不會回滾當前的代碼 |
NEVER | 該傳播機制不支持外層事務,即如果外層有事務就拋出異常 |
MANDATORY | 與NEVER相反,如果外層沒有事務,則拋出異常 |
NESTED |
如果當前存在事務,它將會成爲父級事務的一個子事務,方法結束後並沒有提交,只有等父事務結束才提交 |
相關的測試
1、REQUIRED
a、如果inserA(有事務)當inserA調用inserB(無事務)時,inserB的是否有事務?
運行結果如下:
結果:如果inserA(有事務)當inserA調用inserB(無事務)時,他會給inserB創建一個事務,並合併成一個事務.
b、如果當inserA(無事務)調用insertB(有事務)時,那麼insertB的事務會執行嗎?
運行結果:
結果:如果當inserA(無事務)調用insertB(有事務)時,insertB的事務是不會執行的事務回滾的,即insertB的事務不起作用
結論:
支持當前事務,如果當前沒有事務,則新建事務;
如果當前存在事務,則加入當前事務,合併成一個事務
2、SUPPORTS
1、如果當inserA(required)調用insertB(supports)時,insertB的事務會回滾嗎?
執行結果:
結果:如果當inserA(required)調用insertB(supports)時,insertB的事務會回滾.
b、如果當inserA(無事務)調用insertB(supports)時,insertB的事務會回滾嗎?
結果如下:
結論:如果當inserA(無事務)調用insertB(supports)時,insertB的事務不會回滾
c、如果當inserA(supports)調用insertB(supports)時,insertB的事務會回滾嗎?
結果如下:
結果:如果當inserA(supports)調用insertB(supports)時,insertB的事務不會回滾
d、如果當inserA(supports)調用insertB(required)時,insertB的事務會回滾嗎?
結果如下:
結果:如果當inserA(supports)調用insertB(supports)時,insertB的事務不會回滾
結論
如果當前存在事務,則加入事務。
如果當前不存在事務,則以非事務方式運行,這個和不寫沒區別
REQUIRES_NEW
a、如果當insertLog(無事務)調用insertLogB(事務REQUIRES_NEW)時,會怎樣?
結果如下:
結果:
如果當insertLog(無事務)調用insertLogB(事務REQUIRES_NEW)時,insertLogB創建了事務,並且insertLogB回滾事務,只有user的數據插入成功.
b、如果當insertLog(事務REQUIRES_NEW)調用insertLogB(無事務)時,會怎樣?
結果如下:
結果:如果當insertLog(事務REQUIRES_NEW)調用insertLogB(無事務)時,insertLog創建了事務,並且insertLogB也創建了事務,併合並的了事務,且因報錯,而回滾數據了.
c、如果當insertLog(事務REQUIRES)調用insertLogB(事務REQUIRES_NEW)時,會怎樣?
結果如下:
結果:如果當insertLog(事務REQUIRES)調用insertLogB(事務REQUIRES_NEW)時,insertLogB獨立提交事務,不受調用者的事務影響,父級異常,它也是正常提交
總結
新建事務,如果當前存在事務,則把當前事務掛起
這個方法會獨立提交事務,不受調用者的事務影響,父級異常,它也是正常提交
NOT_SUPPORTED
a、如果當insertLog(無事務)調用insertLogB(無事務NOT_SUPPORTED)時,會怎樣?
結果如下:
結果: 如果當insertLog(無事務)調用insertLogB(無事務NOT_SUPPORTED)時,以非事務方式運行
b、如果當insertLog(事務)調用insertLogB(無事務NOT_SUPPORTED)時,會怎樣?
結果如下:
結果:如果當前存在事務,則把當前事務掛起
總結
以非事務方式運行
如果當前存在事務,則把當前事務掛起
NEVER
a、如果當insertLog(無事務)調用insertLogB(事務NEVER)時,會怎樣?
結果如下:
結果:如果當insertLog(無事務)調用insertLogB(事務NEVER)時,會正常執行,
b、如果當insertLog(有事務)調用insertLogB(事務NEVER)時,會怎樣?
結果如下:
結果:如果當insertLog(required)調用insertLogB(事務NEVER)時,使用事務NEVER會報異常,並且會回滾數據.
總結
該傳播機制不支持外層事務,即如果外層有事務就拋出異常
MANDATORY
a、如果當insertLog(有事務)調用insertLogB(事務MANDATORY)時,會怎樣?
結果如下:
結果:正常執行
b、如果當insertLog(無事務)調用insertLogB(事務MANDATORY)時,會怎樣?
結果如下:
結果:如果當insertLog(無事務)調用insertLogB(事務MANDATORY)時 ,會報異常
結論:
與NEVER相反,如果外層沒有事務,則拋出異常
NESTED
a、如果當insertLog(無事務)調用insertLogB(事務NESTED)時,會怎樣?
結果如下:
結果:如果當insertLog(無事務)調用insertLogB(事務NESTED)時,如果當前沒有事務,則新建事務,並且insertLogB回滾了數據
b、如果當insertLog(有事務,有異常)調用insertLogB(事務NESTED)時,會怎樣?
結果如下:
結果: 如果當insertLog(有事務)調用insertLogB(事務NESTED)時,說明數據回滾了,即自方法正常,父方法有異常的情況下,全部回滾
c、如果當insertLog(有事務)調用insertLogB(事務NESTED,有異常)時,會怎樣?
結果如下:
結果:如果當insertLog(有事務)調用insertLogB(事務NESTED,有異常)時,數據全部回滾.
總結
如果當前存在事務,它將會成爲父級事務的一個子事務,方法結束後並沒有提交,只有等父事務結束才提交
如果當前沒有事務,則新建事務
如果它異常,父級可以捕獲它的異常而不進行回滾,正常提交
但如果父級異常,它必然回滾,這就是和 REQUIRES_NEW 的區別
測試源碼在GitHub上spring-framework下mySpring項目的com.lquan.trans包下(歡迎大家多多給意見,謝謝)
可參考,方便記憶
https://www.cnblogs.com/libin2015/p/12556163.html