讀-讀
狀況:即併發事務相繼讀取相同的記錄
寫-寫
狀況:即併發事務相繼對相同的記錄作出改動
鎖
來實現的。這個所謂的鎖
實際上是一個內存中的結構,在事務執行前原本是沒有鎖的,也就是說一開始是沒有鎖結構
和記錄進行關聯的讀-寫
或寫-讀
狀況:也就是一個事務進行讀取操做,另外一個進行改動操做
髒讀
、不可重複讀
、幻讀
的問題加鎖
加鎖
的方案MVCC
進行的讀取操做稱之爲一致性讀
,或者一致性性鎖讀
,有的地也稱之爲快照讀
。全部普通的SELECT
語句( plain SELECT )在READ COMMITTED
、REPEATABLE READ
隔離級別下都算是一致性讀
,一致性讀
並不會對錶中的任何記錄作加鎖
操做,其餘事務能夠自由的對錶中的記錄作改動併發事務的
讀-讀
狀況並不會引發什麼問題,不過對於寫-寫
、讀-寫
或寫-讀
這些狀況可能會引發一些問題,須要使用MVCC
或者加鎖
的方式來解決它們。在使用加鎖
的方式解決問題時,因爲既要容許讀-讀
狀況不受影響,又要使寫-寫
、讀-寫
或寫-讀
狀況中的操做相互阻塞併發
共享鎖和獨佔鎖指針
Shared Locks
,簡稱S鎖
。在事務要讀取一條記錄時,須要先獲取該記錄的S鎖
排他鎖
,英文名:Exclusive Locks
,簡稱X鎖
。在事務要改動一條記錄時,須要先獲取該記錄的X鎖
T1
首先獲取了一條記錄的S鎖
以後,事務T2
接着也要訪問這條記錄:
T2
想要再獲取一個記錄的S鎖
,那麼事務T2
也會得到該鎖,也就意味着事務T1
和T2
在該記錄上同時持有S鎖
T2
想要再獲取一個記錄的X鎖
,那麼此操做會被阻塞,直到事務T1
提交以後將S鎖
釋放掉T1
首先獲取了一條記錄的X鎖
以後,那麼無論事務T2
接着想獲取該記錄的S鎖
仍是X鎖
都會被阻塞,直到事務T1
提交S鎖
和S鎖
是兼容的,S鎖
和X鎖
是不兼容的,X鎖
和X鎖
也是不兼容的鎖定讀的語句code
加鎖
方式解決髒讀
、不可重複讀
、幻讀
這些問題時,讀取一條記錄時須要獲取該下該記錄的S鎖
,其實這是不嚴謹的,有時候想在讀取記錄時就獲取記錄的X鎖
,來禁用別的事務讀寫該記錄
S鎖
:
SELECT
語句後邊加,若是當前事務執行了該語句,那麼它會爲讀取到的記錄加S鎖
,這樣容許別的事務繼續獲取這些記錄的S鎖
(比方說別的事務也使用語句來讀取這些記錄),可是不能獲取這些記錄的X鎖
(比方說使SELECT ... FOR UPDATE
語句來讀取這些記錄,或者直接修改這些記錄)。若是別的事務想要獲取這些記錄的X鎖
,那麼它們會阻塞,直到當前事務提交以後將這些記錄上的S鎖
釋放掉X鎖
:
SELECT ... FOR UPDATE;
也就是在普通的SELECT
語句後邊加FOR UPDATE
,若是當前事務執行了該語句,那麼它會爲讀取到的記錄加X鎖
,這樣既不容許別的事務獲取這些記錄的S鎖
(比方說別的事務使用語句來讀取這些記錄),也不容許獲取這些記錄的X鎖
(比方說使用SELECT ... FOR UPDATE
語句來讀取這些記錄,或者直接修改這些記錄)。若是別的事務想要獲取這些記錄的S鎖
或者X鎖
,那麼它們會阻塞,直到當前事務提交以後將這些記錄上的X鎖
釋放掉寫操做索引
寫操做
是DELETE
、UPDATE
、INSERT
這三種:
DELETE
操做的過程實際上是先在B+
樹中定位到這條記錄的位置,而後獲取一下這條記錄的X鎖
,而後再執行delete mark
操做。咱們也能夠把這個定位待刪除記錄在B+
樹中位置的過程當作是一個獲取X鎖
的鎖定讀UPDATE
操做時分爲三種狀況:
B+
樹中定位到這條記錄的位置,而後再獲取一下記錄的X鎖
,最後在原記錄的位置進行修改操做。其實咱們也能夠把這個定位待修改記錄在B+
樹中位置的過程當作是一個獲取X鎖
的鎖定讀
B+
樹中定位到這條記錄的位置,而後獲取一下記錄的X鎖
,將該記錄完全刪除掉(就是把記錄完全移入垃圾鏈表),最後再插入一條新記錄。這個定位待修改記錄在B+
樹中位置的過程當作是一個獲取X鎖
的鎖定讀
,新插入的記錄由 INSERT
操做提供的隱式鎖
進行保護DELETE
操做以後再來一次INSERT
操做,加鎖操做就須要按照DELETE
和INSERT
的規則進行了隱式鎖
來保護這條新插入的記錄在本事務提交前不被別的事務訪問前邊提到的
鎖
都是針對記錄的,也能夠被稱之爲行級鎖
或者行鎖
,對一條記錄加鎖影響的也只是這條記錄而已,咱們就說這個鎖的粒度比較細;其實一個事務也能夠在表級別進行加鎖,天然就被稱之爲表級鎖
或者表鎖
,對一個表加鎖影響整個表中的記錄,咱們就說這個鎖的粒度比較粗。給表加的鎖也能夠分爲共享鎖
(S鎖
)和獨佔鎖
(X鎖
)事務
S鎖
:
S鎖
,那麼:
S鎖
S鎖
X鎖
X鎖
X鎖
:
X鎖
(意味着該事務要獨佔這個表),那麼:
S鎖
S鎖
X鎖
X鎖
S鎖
、X鎖
SELECT
、INSERT
、DELETE
、UPDATE
語句時,InnoDB
存儲引擎是不會爲這個表添加表級別的S鎖
或者X鎖
的IS鎖
、IX鎖
InnoDB
存儲引擎的表的某些記錄加S鎖
以前,那就須要先在表級別加一個IS鎖
,當咱們在對使用InnoDB
存儲引擎的表的某些記錄加X鎖
以前,那就須要先在表級別加一個IX鎖
。IS鎖
和IX鎖
的使命只是爲了後續在加表級別的S鎖
和X鎖
時判斷表中是否有已經被加鎖的記錄,以免用遍歷的方式來查看錶中有沒有上鎖的記錄AUTO-INC鎖
MySQL
過程當中,咱們能夠爲表的某個列添加AUTO_INCREMENT
屬性,以後在插入記錄時,能夠不指定該列的值,系統會自動爲它賦上遞增的值行鎖
,也稱爲記錄鎖
,顧名思義就是在記錄上加的鎖行鎖
類型
Record Locks
:有S鎖
和X鎖
之分,當一個事務獲取了一條記錄的S型記錄鎖
後,其餘事務也能夠繼續獲取該記錄的S型記錄鎖
,但不能夠繼續獲取X型記錄鎖
;當一個事務獲取了一條記錄的X型記錄鎖
後,其餘事務既不能夠繼續獲取該記錄的S型記錄鎖
,也不能夠繼續獲取X型記錄鎖
Gap Locks
:能夠用於解決可重複讀級別下的幻讀問題,防止插入幻影記錄Next-Key Locks
: 鎖住某條記錄同時又能夠阻止其餘事務在該條記錄前邊的間隙
插入新紀錄,其是Record Locks
和gap Locks
的合體它既能保護該條記錄,又能阻止別的事務將新記錄插入被保護記錄前邊的間隙
Insert Intention Locks
:一個事務在插入一條記錄時須要判斷一下插入位置是否是被別的事務加了所謂的gap鎖
,若存在,插入操做須要等待,直到擁有的gap鎖
對應的事務提交,事務在等待的時候也須要在內存中生成一個鎖結構
,代表有事務想在某個間隙
中插入新紀錄,可是如今在等待。這種類型的鎖命名爲Insert Intention Locks
,也成爲插入意向鎖
隱式鎖
:一個事務在執行INSERT
操做時,若是即將插入的間隙已經被其餘事務加了gap
鎖,那麼本次INSERT
操做會阻塞,而且當前事務會在該間隙上加一個插入意向鎖
,不然通常狀況下INSERT
操做是不加鎖的鎖結構
與之關聯
鎖結構
中的狀況
鎖所在的事務信息
: 不管是表鎖
仍是行鎖
,都是在事務執行過程當中生成的,哪一個事務生成了這個鎖結構
,這裏就記載着這個事務的信息。其本質是一個指針,經過該指針能夠找到內存中關於該事務的更多信息索引信息
:對於行鎖
來講,須要記錄一下加鎖的記錄是屬於哪一個索引的表鎖/行級信息
:
表鎖
:記載着這是對哪一個表加的鎖,還有其餘的一些信息行鎖
:記載了三個重要的信息
n_bits
屬性表明使用了多少比特位type_mode
:這是一個32位的數,被分紅了lock_mode
、lock_type
和rec_lock_type
三個部分
LOCK_IS
(十進制的0
):表示共享意向鎖,也就是IS鎖
。LOCK_IX
(十進制的1
):表示獨佔意向鎖,也就是IX鎖
。LOCK_S
(十進制的2
):表示共享鎖,也就是S鎖
。LOCK_X
(十進制的3
):表示獨佔鎖,也就是X鎖
。LOCK_AUTO_INC
(十進制的4
):表示AUTO-INC鎖
。LOCK_TABLE
(十進制的16
),也就是當第5個比特位置爲1時,表示表級鎖。LOCK_REC
(十進制的32
),也就是當第6個比特位置爲1時,表示行級鎖rec_lock_type
),使用其他的位來表示。只有在lock_type
的值爲LOCK_REC
時,也就是隻有在該鎖爲行級鎖時,纔會被細分爲更多的類型:
LOCK_ORDINARY
(十進制的0
):表示next-key
鎖 。LOCK_GAP
(十進制的512
):也就是當第10個比特位置爲1時,表示gap鎖
。LOCK_REC_NOT_GAP
(十進制的1024
):也就是當第11個比特位置爲1時,表示記錄鎖
。LOCK_INSERT_INTENTION
(十進制的2048
):也就是當第12個比特位置爲1時,表示插入意向鎖