1. 程式人生 > >MySQL——事務與鎖詳解

MySQL——事務與鎖詳解

事務與鎖詳解

1.事務的定義

一系列的資料庫操作,這些操作必須全部執行,否則全部不執行。例如一些和銀行賬戶存取相關的資料庫操作,必須得保證每一個操作得執行。

2.事務衝突——贓讀、不可重複讀、幻讀

由於為了加快資料庫的操作,需要資料庫支援併發,這樣就可能會產生多個事務同時操作同一張表,這樣就可能產生一些衝突。如下:

  1. 贓讀 事務A讀取的是事務B修改之後的資料,若事務B最後由於某些操作沒完成,導致事務回滾,造成A讀取了錯誤的資料。 關鍵詞:讀後回滾、事務回滾
  2. 不可重複讀 事務B對事務A已經讀取的資料進行了修改,這樣如果事務A再次重新讀取資料的話就會造成資料不一致。關鍵詞:讀後修改、update、delete
  3. 幻讀 事務B對事務A搜尋條件以外的資料進行了修改或增加,造成事務A再次重新讀取資料的時候,發現多了幾行滿足條件的資料。關鍵詞:非讀取資料修改、再次讀取行數增加、insert

既然存在這些衝突,於是下面引出事務的隔離級別概念,他們就是用來解決這些衝突的方案。

3.事務的隔離級別

  1. Read Uncommitted(未提交讀) 事務中的修改,即使沒有提交,其他事務也可以看得到,會導致“髒讀”、“幻讀”和“不可重複讀取”。
  2. Read Commited (提交讀) 大多數主流資料庫的預設事務等級,保證了一個事務不會讀到另一個並行事務已修改但未提交的資料。其實質上是對進行修改但未提交的的資料加了鎖,這樣就避免了事務回滾帶來的贓讀可能
    。 但不能避免“幻讀”和“不可重複讀取”,因為該級別只是對修改操作的資料加了鎖,並未對讀取操作的資料加鎖。不能避免其他事務對這些已讀取的資料進行修改
  3. Repeatable Read(重複讀) 保證了一個事務不會修改已經由另一個事務讀取但未提交(回滾)的資料。其實質上,就是對已讀取但未提交的資料加了鎖,這樣就避免了其他事務對這些資料進行修改,避免了“髒讀取”和“不可重複讀取”的情況。 但不能避免“幻讀”,因為幻讀是對非讀取的資料進行操作,而這一級別的隔離是對已讀取和已操作的資料進行限制。MySQL預設事務隔離級別
  4. Serializable (序列化) 最嚴格的級別,事務序列執行,資源消耗最大。最嚴格的級別,事務序列執行,資源消耗最大。每一個事務進行操作時,都對錶進行加鎖,不允許其他事務進行操作。

4.MVCC(多版本併發控制)

後來為了解決幻讀,引入了MVCC(多版本併發控制)機制。下面簡單介紹一下: 其實質上是通過對錶增加一個版本欄位來實現的。比如INnoDB中的實現機制,它通過對每個表增添版本起始欄位(建立時的版本號刪除時的版本號)來進行版本控制。每開始一個新的事務,系統版本號都會自動遞增。事務開始時刻的系統版本號會作為事務的版本號。

InnoDB會根據以下兩個條件檢查每行記錄:

  1. InnoDB只查詢版本早於當前事務版本的資料行(也就是,行的系統版本號小於或等於事務的系統版本號),這樣可以確保事務讀取的行,要麼是在事務開始前已經存在的,要麼是事務自身插入或者修改過的。
  2. 行的刪除版本要麼未定義,要麼大於當前事務版本號。這可以確保事務讀取到的行,在事務開始之前未被刪除。

5.鎖的概念

從上面事務的相關概念,可以發現,要想實現事務的隔離級別,也可以說是為了解決併發衝突,我們必須得依靠鎖。鎖是一種實現事務隔離級別和併發的一種機制。 根據處理策略的不同,在不同的角度便有不同的鎖分類:

  1. 功能:共享鎖(讀鎖)、排它鎖(寫鎖)
  2. 粒度:表鎖、行鎖
  3. 時間: 樂觀鎖(提交前):假定不發生併發衝突,只在提交時檢查是否違反資料完整性 悲觀鎖(事務開始後):假定會發生併發衝突,遮蔽一切可能違法資料完整性的操作

我們可以發現MVCC實際上就是一種樂觀鎖機制,它就是在提交前檢查版本號是否滿足條件。但並不是任何場景都適合樂觀鎖機制。 比如update、insert、delete非常頻繁的場景下,樂觀鎖機制就不適合,因為這樣會造成大量的事務回滾操作,大量浪費時間。 相反在查詢操作比例大於增刪改操作時,就適合用樂觀鎖機制。