mysql锁之行级锁

概念


行级锁就是锁住表中指定行的记录。

行锁原理


InnoDB行锁是通过给索引项加锁来实现的,如果没有建立索引,那么采用表默认的隐式主键来锁定。

innodb引擎提供行锁种类


  1. Record Lock:单个行记录上加锁。锁定的是索引项,如果没有设置索引,将使用隐式的主键锁定。
  2. Gap Lock:间隙锁,不包含本身记录的锁定范围。
  3. Next-Key Lock:Record Lock+Gap Lock。锁定范围且包含自身记录。
    InnoDB默认存储引擎是REPEATABLE READ模式,Next-Key Lock算法是默认的行记录算法。
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

行锁的实现方式


共享锁、排他锁

Record Lock(单条记录锁)

  • 锁定范围:当前单条记录。

session1 session2
set autocommit = 0; set autocommit = 0;
select * from edu_user where id = "5045dfba5f5b4cb5b805c379fc538bcb" for update;
成功:select * from edu_user;
成功:select * from edu_user where id = "1234df4446cb4cb6bc2f639830b12345" for update;
阻塞:select * from edu_user where id = "5045dfba5f5b4cb5b805c379fc538bcb" for update;
commit;
执行阻塞内容
commit;

说明:锁住了id为5045dfba5f5b4cb5b805c379fc538bcb的记录,其他行记录可以查询,也可以锁操作、读写。

Next-Key Lock(范围锁)


  • 设计范围锁的目的:解决幻读问题(Phantom Problem)。
  • 什么是幻读:就是在同一事务中,连续执行两次同样的sql语句出现不同结果,第二次sql语句可能会返回之前不存在的行。
  • 正常锁定范围:[prev_val,where_val)、[where_val,post_val)。
  • 范围锁防止幻读:当前会话A会锁定值的前面区域和后面区域,防止在操作过程中,会话B插入了值,造成会话C读取两次结果不同。

操作:

session1 session2
set autocommit = 0; set autocommit = 0;
select * from edu_test where a_val = '11' for update;
成功:insert into edu_test select 6, '9', '9';
成功:insert into edu_test select 7, '14', '14';
成功:insert into edu_test select 9, '13', '13';
阻塞:insert into edu_test select 10, '12', '12';
阻塞:insert into edu_test select 11, '11', '11';
阻塞:insert into edu_test select 12, '10', '10';
commit
commit;
执行阻塞内容

说明:a_val非主键值设置了索引,a_val值为11上排他锁,那么锁定的范围应该为[10,11)、[11,13)。

Next-Key Lock 退化为 Record Lock


  • 结论:当查询的索引含有唯一属性时,innodb会对Next-Key Lock优化,将其降级为Record Lock,即锁住索引本身,而不是范围。
  • 锁定范围:当前单条唯一记录。

操作:

session1 session2
set autocommit = 0; set autocommit = 0;
select * from edu_test where a_val = '11' for update;
成功:insert into edu_test select 6, '12', '12';
commit;
commit

说明:a_val非主键值设置为唯一索引,a_val值为11上了排他锁,那么锁定只为a_val=11的记录,其他记录不锁定,当前锁已经退化为了单条记录锁,如果硬插入a_val=11的记录,那么只会报值重复错误,锁粒度减小,提高了并发性。

Next-Key Lock 退化为 Gap Lock


  • 结论:当查询的索引的值不存在时,那么innodb会对Next-Key Lock优化,将其退化为Gap Lock。
  • 锁定范围:[prev_val,post_val)。

操作:

session1 session2
set autocommit = 0; set autocommit = 0;
select * from edu_test where a_val = '12' for update;
成功:insert into edu_test select 6, 9, '9';
成功:insert into edu_test select 7, 10, '10';
成功:insert into edu_test select 8, 14, '14';
成功:insert into edu_test select 9, 13, '13';
阻塞:insert into edu_test select 10, 11, '11';
阻塞:insert into edu_test select 11, 12, '12';
commit
commit;
执行阻塞内容

说明:a_val非主键值设置了索引,a_val设置了不存在的排他锁,这样innodb会对Next-Key Lock优化,将其退化为Gap Lock。锁定范围是[11, 13)。

order by 排序情况


order by排序会先将当前需要查询的结果排序,然后根据查询索引值前后加锁。

  • 锁定范围:(prev_val,post_val]。

操作:

session1 session2
set autocommit = 0; set autocommit = 0;
select * from edu_test where a_val = 20 order by a_val desc for update;
成功:insert into edu_test select 6, 12, '12';
成功:insert into edu_test select 7, 32, '32';
成功:insert into edu_test select 8, 31, '31';
阻塞:insert into edu_test select 9, 13, '13';
阻塞:insert into edu_test select 10, 25, '25';
commit
commit;
执行阻塞内容

分析:先倒序排序

31, 20, 13, 11, 10

说明:当前索引值a_val为20,那么锁定范围为(31,13]。

范围查询情况


  • 锁定范围:(prev_val,val1]、(val1,val2]、(val2,post_val]。

操作:

session1 session2
set autocommit = 0; set autocommit = 0;
select * from edu_test where a_val < 20 and a_val > 11 order by a_val desc for update;
成功:insert into edu_test select 6, 31, '31';
阻塞:insert into edu_test select 7, 10, '10';
commit
commit;
执行阻塞内容

分析:先倒序排序

31, 20, 13, 11, 10

说明:当前索引值a_val为小于20、大于11,那么锁定范围为(31,10]。

参考


《MySQL技术内幕》InnoDB存储引擎

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容