[每天進步一點點]mysql筆記整理(二):事務與鎖

毛毛向前衝發表於2020-03-26

一. 事務

定義

事務是資料庫管理系統執行過程中一個邏輯單位,由一個有限的資料庫操作序列構成。

說明:

  1. 它是資料庫最小的工作單元。
  2. 它包含一個或者多個DML語句,包括:insert、update、delete。單條的DDL(create drop)和DCL(grant revoke)也會有事務。

事務是和儲存引擎對應的,引用mysql官網

特性

  • Atomicity原子性

對資料庫的操作要麼全部成功,要麼全部失敗,不可能出現部分成功或者失敗。如果前邊的操作成功了,後邊的操作失敗了,這個時候會回滾。

在InnoDB中,回滾是是通過undo log來實現的,undo log記錄了資料修改之前的值(邏輯日誌),如果發生異常,就可以用undo log來實現回滾操作。

  • Consistent一致性

一致性是指資料庫的完整性約束沒有被破壞,事務執行的前後都是合法的資料狀態。比如主鍵必須是唯一的。

  • Isolation隔離性

在多個事務對錶或者行進行併發操作,應該互相不干擾的,通過這種方式,也就是最終保證業務資料的一致性。

  • Durable永續性

對資料的操作,如insert、update、delete,只要事務提交成功,那麼資料結果就是永久性的,不能因為系統的當機或者資料庫的重啟恢復到原來的初始狀態。

永續性是通過redo log和double write雙寫緩衝來實現的。我們運算元據的時候,首先會將資料寫到buffer pool中,同時記錄redo log,如果在刷盤(刷盤:將資料寫入磁碟)之前出現異常,在重啟之後就可以讀取redo log裡面的內容,然後將資料寫入磁碟來保證資料的永續性。

引數

手動開始事務有兩種方式

  1. begin開啟事務。
  2. start transaction開啟事務

結束事務也有兩種方式

  1. commit提交一個事務
  2. rollback回滾一個事務

說明:在客戶端的連線中斷時,事務也會中斷。

在InnoDB中,autocommit引數預設是on,代表自動開啟事物和自動提交事務。

事務隔離級別

名稱解釋

  • 髒讀

在一個事務裡面,由於其他的時候修改了資料並且沒有提交,而且導致了前後兩次讀取的資料不一致的情況,這種事物併發的問題,我們通常稱為髒讀。也可以理解為一次事務讀取到了其他事務未提交的資料的情況。

  • 不可重複讀

同樣在兩個事務的情況下,一個事務讀取到了其它事務已提交的資料導致前後兩次讀取的資料不一致的情況,我們通常情況下稱為不可重複讀。

  • 幻讀

由於其它事務插入資料,導致另一事務前後讀取到的資料不一致的情況我們稱它為幻讀。

隔離級別

  • Read Uncommitted未提交讀

一個事務讀取到其它事務未提交的資料,這種情況會出現髒讀,它沒有解決任何的問題。

  • Read Committed已提交讀

一個事務只能讀取到其它事務已提交的資料,不能讀取到其它事務未提交的資料,它解決了髒讀的問題,但是會出現不可重複讀的問題。

  • Repeatable Read可重複讀

在同一個事務裡面多次讀取同樣的資料結果都是一樣的,它解決了不可重複讀的問題,但是沒有解決幻讀問題。

  • Serializable序列化

所有的事務都是序列執行的,所有的資料操作都是需要等待之前操作完成才能執行,這樣就不存在事務的併發操作。它解決了所有併發事務導致的問題。

事務隔離級別 髒讀 不可重複讀 幻讀
Read Uncommitted 可能 可能 可能
Read Committed 不可能 可能 可能
Repeatable Read 不可能 不可能 InnoDB儲存引擎不可能
Serializable 不可能 不可能 不可能

說明:mysql InnoDB預設使用RR(Repeatable Read)。事務隔離級別越高,事務的併發度就越低,InnoDB在RR的級別就解決了幻讀問題,這也是在InnoDB儲存引擎的情況下預設使用RR的原因,它既保證資料的一致性,又支援較高的併發。

解決方案

如果要解決讀一致性的問題,保證一個事務前後兩次讀取的資料結果一致,實現事務的隔離,一般都是採用加鎖來解決這種問題。

LBCC

Lock Based Concurrency Control:基於鎖的併發控制,在我們要讀取資料的時候,鎖定我們要操作的資料,不允許其它事務來修改。這樣其實就是意味著不支援併發的讀寫操作,會影響運算元據的效率。

MVCC

在LBCC存在效率問題的情況下,就出現了另一種解決方案MVCC。

Multi Version Concurrency Control:核心就是們可以查詢在我們這個事務開始之前已經存在的資料,即使它在後面被修改或者刪除。在我們這個事務之後新增的資料是查詢不到的。

InnoDB為每行記錄都實現了兩個隱藏欄位:

  • DB_TRX_ID:6位元組,插入或更新行的最後一個事務的事務的id,事務編號是自動遞增的。(可以理解為建立版本號)
  • DB_ROLL_PTR:7位元組,回滾指標。(可以理解為刪除版本號)

共享鎖

Shared Locks:我們獲取了一行資料的讀鎖以後,可以用來讀取資料,所以它也叫做讀鎖,而且多個事務可以共享一個把讀鎖。可以通過lock in share mode手動加一把讀鎖。例如:select * from table lock in share moe;

釋放鎖有兩種方式,它包括:提交事務和結束事務。只要事務結束,鎖就會自動釋放。

排它鎖

Exclusive Locks:它是用來運算元據的,所以也叫做寫鎖。只要一個事務獲取了一行資料的排它鎖,其它事務就不能在獲取這行資料的共享鎖和排它鎖。可以通過for update給一行資料加上一個排它鎖,例如:select * from table where ID = 1 for update;

釋放鎖同共享鎖一樣。

意向鎖

意向鎖其實是由資料庫自己維護的。當我們給一行資料加上共享鎖之前,資料庫會自動在這張表上面加一個意向鎖。當我們給一行資料加上排它鎖之前,資料庫會自動在這張表上面加一個意向排它鎖。

意向鎖存在的意義是當我們準備給一張表加上鎖的時候,我們首先要判斷是否有其他事務鎖定了其中某些行,如果有的話,肯定就不能加表鎖,那麼這個時候我們會去掃描整個表,如果資料量比較大的話,加鎖的效率就變的非常低。有了意向鎖後,我們只要判斷這張表上有沒有意向鎖就可以了。意向鎖也可以簡單的理解為一個標誌。

記錄鎖

當我對於唯一性的索引(唯一索引和主鍵索引)使用等值查詢,能夠精確匹配到一條記錄的時候,這種情況使用的就是記錄鎖。

間隙鎖

當我們查詢的記錄不存在,沒有命中任何一條記錄的時候,無論是用等值查詢還是範圍查詢,它使用的都是間隙鎖。

間隙鎖主要是阻塞insert插入操作,相同的間隙鎖之間不衝突。間隙鎖只有在RR的情況下存在。

臨鍵鎖

當我們使用範圍查詢的時候,不僅僅命中了多行記錄,而且還包含了Gap Lock(間隙鎖),這種情況下我們使用的就是臨鍵鎖。它是mysql裡面預設的行鎖演算法,相當於記錄鎖+間隙鎖。

說明:還有表鎖和行鎖,這兩個比較簡單,一個就是鎖定整張表,一個是鎖定特定的行。

總結

瞭解了鎖之後,我們可以回過頭來看看事務的隔離級別;

  • RU(Read Uncommitted):不加鎖
  • RR(Repeatable Read):普通的select使用快照讀(snapshot read),底層使用的是MVCC來實現。加鎖的select(select ...... lock in share mode/select ...... for update)以及更新刪除操作(update、delete)等語句使用的是當前讀(current read),底層使用記錄鎖、間隙鎖或者臨鍵鎖。
  • RC(Read Committed):普通方式下和RR相同。加鎖的select操作都是使用的記錄鎖,因為RC隔離級別下沒有Gap Lock。除了兩種特殊情況下,外來鍵約束檢查(foreign-key constraint checking)以及重複鍵檢查(duplicate-key checking)時會使用間隙鎖封鎖區間。所以RC會出現幻讀的問題。
  • Serializable:所有的select語句都會被隱式的轉化為select ...... lock in share mode,會和update、delete互斥。


  • 整理不易,轉載請註明出處,喜歡的小夥伴可以關注公眾號檢視更多喜歡的文章。

  • 聯絡方式:4272231@163.com

  • QQ:95472323

  • 微信:ffj2000

相關文章