分類
聲明式事務
建立在aop之上的,我們常用的事務
聲明式事務是編程式事務 + AOP 技術包裝
編程式事務
基於pojo的事務,我們用的較少
我們需要在代碼中顯式調用 beginTransaction()、commit()、rollback() 等事務管理相關的方法,這就是編程式事務管理。
隔離級別 - isolation
類似於數據庫中的事務隔離級別
通過設置Transactional的屬性isolation 來設置
1、Isolation.DEFAULT
事務默認的隔離級別,使用數據庫默認的隔離級別。
2、Isolation.READ_UNCOMMITTED
這是事務最低的隔離級別,它充許別外一個事務可以看到這個事務未提交的數據。
這種隔離級別會產生髒讀,不可重複讀和幻讀。
3、Isolation.READ_COMMITTED
保證一個事務修改的數據提交後才能被另外一個事務讀取。
另外一個事務不能讀取該事務未提交的數據。這種事務隔離級別可以避免髒讀出現,但是可能會出現不可重複讀和幻讀。
4、Isolation.REPEATABLE_READ
這種事務隔離級別可以防止髒讀,不可重複讀。但是可能出現幻讀。
5、Isolation.SERIALIZABLE
這是花費最高代價但是最可靠的事務隔離級別。事務被處理爲順序執行。除了防止髒讀,不可重複讀外,還避免了幻讀。
傳播行爲 - propagation
在SpringBoot中通過Transactional的propagation屬性來指定
7種傳播行爲,常用的爲前兩種
1、REQUIRED
默認,如果調用者沒有事務,則開啓事務,如果調用者有事務,則加入該事務
例如:a調用b,如果a有事務,b回滾了,a也會回滾
2、REQUIRES_NEW
開啓一個自己獨立的事務,調用者有事務也會先掛起
例如:a調用b,a事務回滾,b不會回滾,但是b異常回滾了,a也會回滾
3、SUPPORTS
如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行。
用於非核心業務,即使報錯也不需要回滾的代碼(看調用者的事務必要性)。
例如:a調用b,a存在事務,b加入;如果a沒有事務,b也以非事務方式執行。
4、NOT_SUPPORTED
以非事務方式運行,如果當前存在事務,則把當前事務掛起。
它可以幫助將事務極可能的縮小,因爲一個事務越大,它存在的風險也就越多,所以在處理事務的過程中,要保證儘可能的縮小範圍。
例如:a調用b,b中以非事物狀態運行,b報錯了,a事務也不會回滾
5、NEVER
以非事務方式運行,如果當前存在事務,則拋出拋出Runtime 異常,強制停止執行。
例如:a調用b,如果a有事務,直接拋出Runtime異常
6、MANDATORY
如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。也就是說,MANDATORY 要求上下文中必須要存在事務,否則就會拋出異常。
例如:a調用b,如果a沒有事務,b直接拋異常
7、NESTED
如果當前存在事務,則創建一個事務作爲當前事務的嵌套事務(子事務)來運行;如果當前沒有事務,則該取值等價於 REQUIRED。
例如:a調用b,a回滾,b也跟着你回滾,但是b回滾,不會影響a和其他子事務
其他屬性
1、timeout
事務的超時時間,單位爲秒
2、readOnly
該屬性用於設置當前事務是否爲只讀事務,設置爲true表示只讀,false則表示可讀寫,默認值爲false
如果一個事務只涉及到只讀,可以設置爲true
3、rollbackFor 屬性
用於指定能夠觸發事務回滾的異常類型,可以指定多個異常類型
默認是在RuntimeException
和Error
上回滾
4、noRollbackFor
拋出指定的異常類型,不回滾事務,也可以指定多個異常類型
失效情況
我們討論的是基於默認的事務傳播級別:REQUIRED
1、mysql的數據庫引擎是MyISAM
2、註解加的方法的訪問修飾符不是public
3、事務中異常被捕捉處理,沒有拋出
4、同類方法調用,a調用b方法,b方法事務失效
爲什麼此時事務失效?
其實原因很簡單,Spring在掃描Bean的時候會自動爲標註了
@Transactional
註解的類生成一個代理類(proxy),當有註解的方法被調用的時候,實際上是代理類調用的,代理類在調用之前會開啓事務,執行事務的操作,但是同類中的方法互相調用,相當於this.B()
,此時的B方法並非是代理類調用,而是直接通過原有的Bean直接調用,所以註解會失效。
5、如果使用了Spring + MVC,則 context:component-scan
重複掃描問題可能會引起事務失效
站在巨人的肩膀上學習和整理,如有紕漏,歡迎大家指出交流!