Spring事務和數據庫事務的藕斷絲連

什麼是事務?

所謂事務,它是一個操作序列,這些操作要麼都執行,要麼都不執行,它是一個不可分割的工作單位。

  • 例如, 銀行轉帳工作:從一個帳號扣款並使另一個帳號增款,這兩個操作要麼都執行,要麼都不執行。

事務 ACID 特性

數據庫事務必須具備 ACID 特性,ACID 是 Atomic(原子性)、Consistency(一致性)、Isolation(隔離 性)和 Durability(持久性)的英文縮寫。

  • 原子性:一個事務是一個不可分割的工作單位,要不全部執行,要不全部不執行。
  • 一致性:事務執行前和後,必須都保持一致性或完整性。
  • 隔離性:一個事務在執行的過程中,不受其他事務的影響。
  • 持久性:當一個事提交後,對數據庫的改變是永久性的,不會被回滾。

數據庫管理系統採用鎖機制來實現事務的隔離性。當多個事務同時更新數據庫中相同的數據時,只允許持有鎖的事務能更新該數據,其他事務必須等待,直到前一個事務釋放了鎖,其他事務纔有機會更新該數據。

併發事務帶來的問題

相對於串行處理來說,併發事務處理能大大增加數據庫資源的利用率,提高數據庫系統的事務吞吐量,從而可以支持可以支持更多的用戶。但併發事務處理也會帶來一些問題,主要包括以下幾種情況。

  • 更新丟失(Lost Update):當兩個或多個事務選擇同一行,然後基於最初選定的值更新該行時,由於每個事務都不知道其他事務的存在,就會發生丟失更新問題——最後的更新覆蓋了其他事務所做的更新。
    • 例如,兩個編輯人員製作了同一文檔的電子副本。每個編輯人員獨立地更改其副本,然後保存更改後的副本,這樣就覆蓋了原始文檔。最後保存其更改保存其更改副本的編輯人員覆蓋另一個編輯人員所做的修改。如果在一個編輯人員完成並提交事務之前,另一個編輯人員不能訪問同一文件,則可避免此問題。
  • 髒讀(Dirty Reads):一個事務正在對一條記錄做修改,在這個事務修改並提交前,這條記錄的數據就處於不一致狀態;這時,另一個事務也來讀取同一條記錄,如果不加控制,第二個事務讀取了這些“髒”的數據,並據此做進一步的處理,就會產生未提交的數據依賴關係。這種現象被形象地叫做“髒讀”。
    • 爲什麼會出現髒讀,因爲你對數據庫的任何修改都會是立即生效的,至於別人能不能看到主要取決與你 是否加鎖了,數據庫的執行與事務沒有關係,事務只是保證對數據庫所做的操作會不會撤銷而已,mysql默認是行級鎖,修改時只會對修改的那幾行加鎖,加鎖期間其他用戶線程是看不到修改結果的,所以會導致不可重複讀和幻讀的問題;
  • 不可重複讀(Non-Repeatable Reads):一個事務在讀取某些數據已經發生了改變、或某些記錄已經被刪除了!這種現象叫做“不可重複讀”。
  • 幻讀(Phantom Reads):一個事務按相同的查詢條件重新讀取以前檢索過的數
    • 幻讀的原因:因爲mysql默認是通過行級鎖來實現的,而不是表級鎖,那麼在修改期間其他線程當然可以新插入數據了;如果使用了mysql表級鎖的引擎如:MyIsAM,幻讀就不可能出現;

  • 髒讀和不可重複讀的區別在於讀的時候是否加了讀共享鎖,不可重複讀加了讀共享鎖;髒讀是寫的時候加了排他鎖

Spring事務

Spring事務的五種隔離級別

隔離級別 解釋
DEFAULT:採用 DB 默認的事務隔離級別 MySql 默認爲 REPEATABLE_READ;Oracle 默認爲:READ_COMMITTED;
READ_UNCOMMITTED:讀未提交 未解決任何併發問題。
READ_COMMITTED:讀已提交 解決髒讀,存在不可重複讀與幻讀。
REPEATABLE_READ:可重複讀 解決髒讀、不可重複讀。存在幻讀。
SERIALIZABLE:串行化 不存在併發問題。

Spring事務的七種傳播行爲

所謂事務傳播行爲是指,處於不同事務中的方法在相互調用時,執行期間事務的維護情況。

比如,A 事務中的方法 a() 調用 B 事務中的方法 b(),在調用執行期間事務的維護情況,就稱爲事務傳播行爲。事務傳播行爲是加在方法上的。

  • REQUIRED:指定的方法必須在事務內執行。若被調用方法當前存在事務,就加入到調用後的事務中;若被調用方法當前沒有事務,則創建一個新事務。這種傳播行爲也是 Spring 默認的事務傳播行爲
  • SUPPORTS:指定的方法支持當前事務,但若被調用方法當前沒有事務,調用方法也可以以非事務方式執行。
  • MANDATORY:指定的方法必須在當前事務內執行,若被調用方法當前沒有事務,則直接拋出異常。
  • REQUIRES_NEW:總是新建一個事務,若被調用方法當前存在事務,就將當前事務掛起,創建一個新事務(只包含自身),直到新事務執行完畢。
  • NOT_SUPPORTED:指定的方法不能在事務環境中執行,若被調用方法當前存在事務,就將當前事務掛起。
  • NEVER:指定的方法不能在事務環境下執行,若被調用方法當前存在事務,就直接拋出異常。
  • NESTED:指定的方法必須在事務內執行。若當前存在事務,則在嵌套事務內執行;若當前沒有事務,則創建一個新事務。

數據庫事務

數據庫事務的四種隔離級別

隔離級別 解釋
READ_UNCOMMITTED:讀未提交 未解決任何併發問題。
READ_COMMITTED:讀已提交 解決髒讀,存在不可重複讀與幻讀。
REPEATABLE_READ:可重複讀 解決髒讀、不可重複讀。存在幻讀。
SERIALIZABLE:串行化 不存在併發問題。
  • 4種事務隔離級別從上往下,級別越高,併發性越差,安全性就越來越高。

看到這兒,聰明的你是不是發現了點什麼。

聯繫

事務原本是數據庫中的概念,用於數據訪問層。但一般情況下,我們經常在業務層操作數據庫,因此需要將事務提升到業務層,即 Service 層。這樣做是爲了能夠使用事務的特性來管理具體的業務。Spring事務本質上其實是使用了數據庫的事務,而數據庫事務的底層原理是使用了鎖機制。

  • 總的來說,Spring的事務是對數據庫的事務的封裝,最後本質的實現還是在數據庫。假如數據庫不支持事務的話,Spring的事務是沒有作用的。數據庫的事務說簡單就只有開啓、回滾和關閉。
  • Spring對數據庫事務的包裝,原理就是拿一個數據連接,根據Spring的事務配置,操作這個數據連接對數據庫進行事務開啓、回滾或關閉操作。但是Spring除了實現這些,還配合Spring的傳播行爲對事務進行了更廣泛的管理。Spring的事務是通過事務管理器 PlatformTransactionManager 接口對象下的實現類進行操作的,其主要用於完成事務的提交、回滾,及獲取事務的狀態信息。

  • PlatformTransactionManager 接口有兩個常用的實現類:
    • DataSourceTransactionManager:使用 JDBC 或 MyBatis 進行持久化數據時使用。
    • HibernateTransactionManager:使用 Hibernate 進行持久化數據時使用。

你知道的越多,你不知道的越多。
有道無術,術尚可求,有術無道,止於術。
如有其它問題,歡迎大家留言,我們一起討論,一起學習,一起進步

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章