在RR條件, id是主鍵,插入五條數(shù)據(jù)
id | name |
---|---|
1 | title1 |
2 | title2 |
3 | title3 |
9 | title9 |
10 | title10 |
session 1 | session 2 |
---|---|
begin; | begin; |
select * from user where id = 6 for update; | |
~ | select * from user where id = 6 for update |
insert into user 6, title6 | |
鎖等待中 | insert into user 6, title6 |
鎖等待解除 | 死鎖,session 2的事務(wù)被回滾 |
我們可以發(fā)現(xiàn)
針對(duì)事務(wù)一:select * from user where id = 6 for update; 第一次查詢,沒(méi)有找到滿足查詢條件的記錄,那么mysql會(huì)加一個(gè)gap鎖
但是事務(wù)2也可以執(zhí)行 select * from user where id = 6 for update;菠净,這個(gè)時(shí)候事務(wù)1和事務(wù)2都有3-9的GAP鎖,2個(gè)事務(wù)都不能執(zhí)行insert id=6的記錄彪杉,會(huì)報(bào)死鎖異常毅往。gap鎖本身的作用是防止后續(xù)的插入操作,因此gap鎖只跟插入相沖突派近,gap鎖之間不沖突攀唯,所以這個(gè)時(shí)候會(huì)發(fā)生死鎖。
我們更換SQL語(yǔ)句改為
SELECT * FROM user
where id >5 and id <7 for update; 其余不變渴丸。 會(huì)發(fā)現(xiàn)兩條select語(yǔ)句會(huì)沖突侯嘀。
引用何登成的解釋?zhuān)?br>
"按照原理來(lái)說(shuō),id>5 and id<7這個(gè)查詢條件谱轨,在表中找不到滿足條件的項(xiàng)戒幔,因此會(huì)對(duì)第一個(gè)不滿足條件的項(xiàng)(id = 9)上加GAP鎖,防止后續(xù)其他事務(wù)插入滿足條件的記錄土童。
而GAP鎖與GAP鎖是不沖突的诗茎,那么為什么兩個(gè)同時(shí)執(zhí)行id>5 and id<7查詢的事務(wù)會(huì)沖突呢?
原因在于献汗,MySQL Server并沒(méi)有將id<7這個(gè)查詢條件下降到InnoDB引擎層敢订,因此InnoDB看到的查詢王污,是id>5,正向掃描楚午。讀出的記錄id=9昭齐,先加上next key鎖(Lock X + GAP lock),然后返回給MySQL Server進(jìn)行判斷矾柜。
MySQL Server此時(shí)才會(huì)判斷返回的記錄是否滿足id<7的查詢條件阱驾。此處不滿足,查詢結(jié)束怪蔑。
因此里覆,id=9記錄上,真正持有的鎖是next key鎖饮睬,而next key鎖之間是相互沖突的租谈,這也說(shuō)明了為什么兩個(gè)id>5 and id<7查詢的事務(wù)會(huì)沖突的原因篮奄。