Mysql 死锁过程及案例详解之记录锁与间隔锁Record Lock Gap Lock
記錄鎖Record Lock與間隔鎖GAP Lock
記錄鎖Record Lock
記錄鎖Record Locks又稱為行鎖,它同時包含索引和間隔鎖。記錄鎖可以是共享鎖也可能是排他鎖。可以通過performance_schema.data_locks表的LOCK_TYPE和LOCK_MODEL來查看。
示意案例
-- Step1 開始事務,更新city的Population字段,這里更新時通過輔助索引里的字段CountryCode。 START TRANSACTION; UPDATE city SET Population = Population + 1 WHERE CountryCode = 'LUX';-- Step2 查看鎖情況。 mysql> SELECT * FROM performance_schema.data_locks \G *************************** 1. row ***************************ENGINE: INNODBENGINE_LOCK_ID: 139740117241856:1067:139740049392448 ENGINE_TRANSACTION_ID: 38181THREAD_ID: 49EVENT_ID: 130OBJECT_SCHEMA: worldOBJECT_NAME: cityPARTITION_NAME: NULLSUBPARTITION_NAME: NULLINDEX_NAME: NULL OBJECT_INSTANCE_BEGIN: 139740049392448LOCK_TYPE: TABLELOCK_MODE: IXLOCK_STATUS: GRANTEDLOCK_DATA: NULL *************************** 2. row ***************************ENGINE: INNODBENGINE_LOCK_ID: 139740117241856:6:20:344:139740049389536 ENGINE_TRANSACTION_ID: 38181THREAD_ID: 49EVENT_ID: 130OBJECT_SCHEMA: worldOBJECT_NAME: cityPARTITION_NAME: NULLSUBPARTITION_NAME: NULLINDEX_NAME: CountryCode OBJECT_INSTANCE_BEGIN: 139740049389536LOCK_TYPE: RECORDLOCK_MODE: XLOCK_STATUS: GRANTEDLOCK_DATA: 'LUX', 2452 *************************** 3. row ***************************ENGINE: INNODBENGINE_LOCK_ID: 139740117241856:6:23:104:139740049389880 ENGINE_TRANSACTION_ID: 38181THREAD_ID: 49EVENT_ID: 130OBJECT_SCHEMA: worldOBJECT_NAME: cityPARTITION_NAME: NULLSUBPARTITION_NAME: NULLINDEX_NAME: PRIMARY OBJECT_INSTANCE_BEGIN: 139740049389880LOCK_TYPE: RECORDLOCK_MODE: X,REC_NOT_GAPLOCK_STATUS: GRANTEDLOCK_DATA: 2452 *************************** 4. row ***************************ENGINE: INNODBENGINE_LOCK_ID: 139740117241856:6:20:326:139740049390224 ENGINE_TRANSACTION_ID: 38181THREAD_ID: 49EVENT_ID: 130OBJECT_SCHEMA: worldOBJECT_NAME: cityPARTITION_NAME: NULLSUBPARTITION_NAME: NULLINDEX_NAME: CountryCode OBJECT_INSTANCE_BEGIN: 139740049390224LOCK_TYPE: RECORDLOCK_MODE: X,GAPLOCK_STATUS: GRANTEDLOCK_DATA: 'LVA', 2434通過結果不難發現這里的意向鎖是排他鎖,狀態是“GRANTED”,第二行里顯示next-key鎖在索引CountryCode上,LOCK_TYPE為記錄。這里結合當前的WHERE條件對應的是鎖定的數據為“’LUX’, 2452”,這里的2452對應的是主鍵的ID。 這里不難驗證city表里CountryCode為’LUX’的主鍵即ID為2452。第三行顯示的鎖的主鍵信息,其中LOCK_TYPE為記錄、LOCK_MODEL為X,REC_NOT_GAP即是個排他鎖,但不是間隔鎖。第四行顯示的間隔鎖的信息(主鍵或者索引里兩個記錄之間的間隔),詳見間隔鎖里的說明。-- Step3 驗證完后還原事務。 Rollback間隔鎖Gap Lock
間隔鎖Gap Locks會鎖定兩條記錄之間的空間,這種鎖往往出現在聚集索引(即主鍵)和輔助索引(非聚集索引的其它索引的統稱)里。
在索引頁的第一條記錄之前和該頁的最后一條記錄之后,分別有偽記錄,稱為下界記錄(infimum record)和上界記錄(supremum record)。
回到記錄鎖(Record Locks)里的例子,即將city表里CountryCode 是’LUX'的記錄(僅有1條)里的Population字段進行更新,加1。如果在執行這個操作的時候,往表city里插入了一條或多條CountryCode 是’LUX'的新記錄,會出現什么問題呢?如果UPDATE先執行,INSERT后執行則沒有問題,如果反過來過來則會出現不一致的情況。即新插入的數據在后面又被更新掉了(這和預期不符)。所以這時需要用到間隔鎖(Gap Lock),它的作用就是鎖定當前索引頁和下一個索引頁這段間隔記錄,即如果有INSERT,那么必須得之前的UPDATE執行完了才能操作。
在記錄鎖的示意案例的第4行里,我們可以看到間隔鎖的相關信息,這里鎖定的是索引頁的‘LVA’, 2434,通過查詢可以知道索引CountryCode的LUX的下一個即是LVA,所以這里鎖定的是索引里對應這條記錄。即在“LUX”“LVA”之間的記錄加了排他的間隔鎖。當然插入CountryCode為LVA的記錄是可以的。
和間隔鎖相關的鎖有next-key locks和predicate locks.next-key鎖時記錄鎖和間隔鎖的組合(詳見記錄鎖里的示例案例)。
*************************** 2. row ***************************
?????????????? ENGINE: INNODB
?????? ENGINE_LOCK_ID: 139740117241856:6:20:344:139740049389536
ENGINE_TRANSACTION_ID: 38181
??????????? THREAD_ID: 49
???????????? EVENT_ID: 130
??????? OBJECT_SCHEMA: world
????????? OBJECT_NAME: city
?????? PARTITION_NAME: NULL
??? SUBPARTITION_NAME: NULL
?????????? INDEX_NAME: CountryCode
OBJECT_INSTANCE_BEGIN: 139740049389536
??????????? LOCK_TYPE: RECORD
??????????? LOCK_MODE: X
????????? LOCK_STATUS: GRANTED
??????????? LOCK_DATA: 'LUX', 2452
*************************** 3. row ***************************
?????????????? ENGINE: INNODB
?????? ENGINE_LOCK_ID: 139740117241856:6:23:104:139740049389880
ENGINE_TRANSACTION_ID: 38181
??????????? THREAD_ID: 49
???????????? EVENT_ID: 130
??????? OBJECT_SCHEMA: world
????????? OBJECT_NAME: city
?????? PARTITION_NAME: NULL
??? SUBPARTITION_NAME: NULL
?????????? INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139740049389880
??????????? LOCK_TYPE: RECORD
??????????? LOCK_MODE: X,REC_NOT_GAP
????????? LOCK_STATUS: GRANTED
??????????? LOCK_DATA: 2452
*************************** 4. row ***************************
?????????????? ENGINE: INNODB
?????? ENGINE_LOCK_ID: 139740117241856:6:20:326:139740049390224
ENGINE_TRANSACTION_ID: 38181
??????????? THREAD_ID: 49
???????????? EVENT_ID: 130
??????? OBJECT_SCHEMA: world
????????? OBJECT_NAME: city
?????? PARTITION_NAME: NULL
??? SUBPARTITION_NAME: NULL
?????????? INDEX_NAME: CountryCode
OBJECT_INSTANCE_BEGIN: 139740049390224
??????????? LOCK_TYPE: RECORD
??????????? LOCK_MODE: X,GAP
????????? LOCK_STATUS: GRANTED
??????????? LOCK_DATA: 'LVA', 2434
這里第2行即是next-key鎖(InnoDB默認的鎖類型),而第3行是在主鍵上的記錄鎖,第行是“LUX”到“LVA”之間的間隔鎖。
predicate locks類似于間隔鎖gap lock,它主要應用于使用坐標的空間場景里。通過使用該鎖鎖定查詢中的最小邊界矩形(minimum bounding rectangle)簡稱MBR,這樣能防止對最小邊界矩形內的數據進行更改已達到數據一致的目的。
示意案例
同記錄鎖。
總結
以上是生活随笔為你收集整理的Mysql 死锁过程及案例详解之记录锁与间隔锁Record Lock Gap Lock的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mysql 死锁过程及案例详解之显式与隐
- 下一篇: 纸杯蛋糕为什么不发?