latch 能夠認爲是應用程序中的鎖,能夠稱爲閂鎖(輕量級的鎖) 由於其要求鎖定的時間必需要很是短,若持續時間長,則會致使應用性能很是差,在InnoDB存儲引擎中,latch又能夠分爲mutex(互斥鎖)和rwlock(讀寫鎖),其目的用來保證併發線程操做臨界資源的正確性,而且沒有死鎖檢測的機制html
在InnoDB存儲引擎中的latch,能夠經過命令SHOW ENGINE INNODB MUTEX 來進行查看mysql
mysql > SHOW ENGINE INNODB MUTEX;算法
lock能夠認爲是數據庫提供的鎖,用來鎖定的是數據庫中的數據。而且通常lock對象僅在事務commit或rollback後進行釋放(不一樣事務隔離級別釋放的時間可能不一樣),lock是有死鎖機制的。sql
在InnoDB存儲引擎中的lock 能夠經過show engine innodb status,information_schema.INNODB_LOCKS,INNODB_TRX,INNODB_LOCK_WATIS信息來查看數據庫
線程獲取lock的流程:併發
在對數據加lock的時候會先對數據所在的頁面添加latch,而後再對數據添加lock,添加完lock後再釋放頁面的Latch。mvc
這種機制主要是爲了保證線程獲取的行數據的一致性和完整性.性能
若是lock被其餘的線程佔有,線程先釋放頁面latch,等待lock,待獲取lock後會再次對頁面添加latch,查看頁面數據是否有改動,而後嘗試再次獲取對應的lockspa
innodb儲存引擎提供了以下兩種標準的行級鎖線程
共享鎖(S) 容許一個事務去讀一行
排他鎖(X) 容許得到排他鎖的事務更新或刪除數據
同時innodb儲存引擎支持多粒度鎖定,爲了支持在不一樣的粒度上進行加鎖操做,innodb支持另外一種額外的鎖方式,稱之爲意向鎖
意向共享鎖(IS) 事務想要得到一張表中某幾行的共享鎖
意向排他鎖(IX)事務想要得到一張表中某幾行的排他鎖
在行鎖的實現上
mysql提供了三種的行鎖的算法
分別是
Record Lock 記錄鎖,單個記錄上的鎖
Gap Lock 間隙鎖,鎖定一個範圍,但不包含記錄自己
Next-key Lock Gap Lock + Record Lock 鎖定一個範圍,而且鎖定記錄自己
非特殊註明 默認在RR隔離級別下進行討論
InnoDb的行鎖是對索引加鎖的,對掃描的行邊掃描邊加鎖,若是走的是二級索引(非聚簇索引)除了須要對二級索引加鎖外,還須要根據二級索引裏面的主鍵信息掃描主鍵的聚簇索引,對主鍵加鎖,
加鎖的數據行數會受到Mysql是否支持Index Condition PushDown而影響(Mysql 5.6支持ICP),加鎖的數量可能遠遠大於知足條件的記錄數量
這裏須要加兩次鎖的緣由是
若是
語句A 使用二級索引對記錄X進行更新操做,
語句B使用聚簇索引對記錄X進行更新操做,
若是A僅對二級索引進行加鎖,那麼併發的語句B將感覺不到語句A的存在,違背了同一條記錄上的更新/刪除必須串行執行的約束
RC級別下 : 無需加鎖,一致性非鎖定讀,使用快照讀,讀取被鎖定行的最新一份數據,所以會出現先後讀取數據不一致的狀況
RR級別下:無需加鎖,一致性非鎖定讀,使用快照讀,讀取事務開始時的行數據版本,所以先後讀到的數據是同樣的
Serializable級別下:使用當前讀,須要加鎖,innodb內部將select語句轉換爲了select … lock in share mode
insert會對插入成功的行加上記錄鎖,不會阻止其餘併發的事務往這條記錄以前插入記錄。在插入以前,會先在插入記錄所在的間隙加上一個插入意向意向鎖(併發的事務能夠對同一個間隙加插入意向鎖鎖)。若是insert 的事務出現了duplicate-key error ,事務會對duplicate index record的記錄加共享鎖。這個共享鎖在併發的狀況下是會產生死鎖的,好比有兩個併發的insert都對要對同一條記錄加共享鎖,而此時這條記錄又被其餘事務加上了排它鎖,排它鎖的事務將這條記錄刪除後,兩個併發的insert操做會發生死鎖。
delete操做僅是將主鍵列中對對應的記錄delete flag設置爲1,記錄並無被刪除,仍是存在於B+樹中
真正的刪除操做被延遲了,最終在purge操做中完成
延遲到purge操做的緣由是的innodb支持mvcc多版本控制,因此記錄不能在事務提交時當即進行刪除,只有當對應的行記錄不被任何其餘事務引用的時候,才能夠由purge進行真正的刪除
delete操做過程當中:
找到知足條件的記錄,而且記錄有效,則對記錄加X鎖
找到知足條件的記錄,可是記錄無效(標識爲刪除),則對記錄加next key鎖、;
未找到知足條件的記錄,則對第一個不知足條件的記錄加Gap鎖,保證沒有知足條件的記錄插入;
對知足條件的記錄next-key鎖,若是是等值匹配而且使用惟一索引或是聚簇索引,那麼能夠只添加記錄鎖
惟一索引中含NULL值的記錄,將不會添加記錄鎖,轉而爲next-key鎖 由於NULL不等於NULL,NULL和任何值比較均返回NULL,包括NULL自己,可是 NULL is NULL
create table `deadlocktest`
(
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`a` bigint(20) unsigned NOT NULL,
`b` bigint(20) unsigned NOT NULL,
`c` bigint(20) unsigned NOT NULL,
`d` bigint(20) unsigned NOT NULL,
`e` bigint(20) unsigned NOT NULL,
PRIMARY KEY(`id`),
UNIQUE KEY `I_a`(`a`),
KEY `I_b` (`b`),
KEY `I_c` (`c`)
)ENGINE=InnoDb ;
insert into deadlocktest (a,b,c,d,e)values(1,999,3,4,5);
insert into deadlocktest (a,b,c,d,e)values(2,998,4,5,6);
insert into deadlocktest (a,b,c,d,e)values(3,997,4,5,6);
insert into deadlocktest (a,b,c,d,e)values(4,996,3,4,5);
...
insert into deadlocktest (a,b,c,d,e)values(1000,1,3,4,5);
事務A |
事務B |
事務C |
begin; |
begin; |
begin; |
insert into deadlocktest (a,b,c,d,e)values(4,996,3,4,5); |
|
|
|
insert into deadlocktest (a,b,c,d,e)values(4,996,3,4,5); |
|
|
|
insert into deadlocktest (a,b,c,d,e)values(4,996,3,4,5); |
rollback; |
|
|
|
1 row affected |
Deadlock found when trying to get lock; try restarting transaction |
事務A 得到排他鎖,插入數據成功
事務B 事務C,由於記錄duplicate-key error轉而持有行的共享鎖
事務A回滾,釋放了持有的排他鎖,事務B和事務C須要得到該行的排他鎖,可是因爲互相都持有對應行的共享鎖,互相等待,形成死鎖
事務A |
事務B |
begin; |
begin; |
update deadlocktest force index(I_b) set e = sleep(5) where b>0; |
|
|
update deadlocktest force index(I_c) set e = sleep(5) where c>2; |
Deadlock found when trying to get lock; try restarting transaction |
Rows matched: 4 Changed: 4 Warnings: 0 |
兩個update事務,加鎖順序不同致使的死鎖
InnoDb的行鎖是對索引加鎖的,對掃描的行邊掃描邊加鎖,若是走的是二級索引(非聚簇索引)除了須要對二級索引加鎖外,還須要根據二級索引裏面的主鍵信息掃描主鍵的聚簇索引,對主鍵加鎖
事務A |
事務B |
事務B |
begin; |
begin; |
begin |
delete from deadlocktest where a=550 |
|
|
|
delete from deadlocktest where a=550 |
|
|
delete from deadlocktest where a=550 |
|
commit; | 0 rows affected | Deadlock found when trying to get lock; try restarting transaction |
delete操做僅是將主鍵列中對對應的記錄delete flag設置爲1,實際的刪除延遲到purge中
delete刪除時若是找到知足條件的記錄,可是記錄無效(標識爲刪除),則對記錄加next key鎖、;
死鎖日誌
3個delete的死鎖比較難以復現,我是利用以下腳本完成的
MY_DB="mysql -hxxx -Pxxx -uxxx -pxxx"
while :
do
echo "use test;begin; delete from deadlocktest where a=499;rollback;" | $MY_DB
done
該類delete死鎖的出現條件
一、針對惟一索引上等值查詢的刪除
二、有3個以上併發刪除操做
三、事務的隔離級別是RR
四、INNODB儲存引擎
https://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html