MySQL中的锁4-插入意向锁和自增锁

插入意向锁(Insert Intention Lock)

插入意向锁本质上可以看成是一个Gap Lock

  • 普通的Gap Lock 不允许 在 (上一条记录,本记录) 范围内插入数据
  • 插入意向锁Gap Lock 允许 在 (上一条记录,本记录) 范围内插入数据

插入意向锁的作用是为了提高并发插入的性能, 多个事务 同时写入 不同数据 至同一索引范围(区间)内,并不需要等待其他事务完成,不会发生锁等待。

插入的过程

假设现在有记录 10, 30, 50, 70 ;且为主键 ,需要插入记录 25 。

  1. 找到 小于等于25的记录 ,这里是 10
  2. 找到 记录10的下一条记录 ,这里是 30
  3. 判断 下一条记录30 上是否有锁
    3.1 判断 30 上面如果 没有锁 ,则可以插入
    3.2 判断 30 上面如果有Record Lock,则可以插入
    3.3 判断 30 上面如果有Gap Lock/Next-Key Lock,则无法插入,因为锁的范围是 (10, 30) /(10, 30] ;在30上增加insert intention lock( 此时处于waiting状态),当 Gap Lock / Next-Key Lock 释放时,等待的事物( transaction)将被 唤醒 ,此时 记录30 上才能获得 insert intention lock ,然后再插入 记录25

注意:一个事物 insert 25 且没有提交,另一个事物 delete 25 时,记录25上会有 Record Lock

插入意向锁演示

数据准备

mysql> desc a;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| b     | int(11) | NO   | PRI | NULL    |       |
+-------+---------+------+-----+---------+-------+
1 row in set (0.00 sec)

mysql> select * from a;
+----+
| b  |
+----+
| 10 |
| 11 |
| 13 |
| 20 |
+----+
4 rows in set (0.00 sec)

开启两个会话,两个会话事务的隔离级别都设置为REPEATABLE-READ

Time 会话A 会话B
1 begin begin
2 select * from a where a<=13 for update
3 insert into a values (12)
-- waiting...... (被阻塞了,在这里等待)

此时执行show engine innodb status\G语句会看到以下结果

---TRANSACTION 4424, ACTIVE 7 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 3, OS thread handle 140018685810432, query id 240 localhost root update
--等待插入的SQL
insert into a values(12)
------- TRX HAS BEEN WAITING 7 SEC FOR THIS LOCK TO BE GRANTED:
--插入记录12的事物等待中(被终端会话A中的事物阻塞了),等待获得插入意向锁(lock_mode X locks gap before rec insert intention waiting)
RECORD LOCKS space id 37 page no 3 n bits 72 index PRIMARY of table `test`.`a` trx id 4424 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 8000000d; asc     ;;
 1: len 6; hex 000000001140; asc      @;;
 2: len 7; hex b400000128011c; asc     (  ;;

------------------
TABLE LOCK table `test`.`a` trx id 4424 lock mode IX
RECORD LOCKS space id 37 page no 3 n bits 72 index PRIMARY of table `test`.`a` trx id 4424 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 8000000d; asc     ;;
 1: len 6; hex 000000001140; asc      @;;
 2: len 7; hex b400000128011c; asc     (  ;;

---TRANSACTION 4423, ACTIVE 55 sec
2 lock struct(s), heap size 1136, 4 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 241 localhost root starting
show engine innodb status
TABLE LOCK table `test`.`a` trx id 4423 lock mode IX
RECORD LOCKS space id 37 page no 3 n bits 72 index PRIMARY of table `test`.`a` trx id 4423 lock_mode X
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 8000000a; asc     ;;
 1: len 6; hex 00000000113f; asc      ?;;
 2: len 7; hex b3000001270110; asc     '  ;;

Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 8000000b; asc     ;;
 1: len 6; hex 000000001140; asc      @;;
 2: len 7; hex b4000001280110; asc     (  ;;

Record lock, heap no 4 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 8000000d; asc     ;;
 1: len 6; hex 000000001140; asc      @;;
 2: len 7; hex b400000128011c; asc     (  ;;

Record lock, heap no 5 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 80000014; asc     ;;
 1: len 6; hex 000000001145; asc      E;;
 2: len 7; hex b70000012b0110; asc     +  ;;

Time 会话A 会话B
1 begin begin
2 select * from a where a<=13 for update
3 insert into a values (12)
-- waiting...... (被阻塞了,在这里等待)
4 commit
5 输出:Query OK, 1 row affected (17.40 sec)
前提条件是insert操作的锁没有超时

此时事务B插入成功但是还未commit,再执行show engine innodb status\G语句,会有以下输出:

---TRANSACTION 4425, ACTIVE 26 sec
2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1
MySQL thread id 3, OS thread handle 140018685810432, query id 247 localhost root
TABLE LOCK table `test`.`a` trx id 4425 lock mode IX
RECORD LOCKS space id 37 page no 3 n bits 72 index PRIMARY of table `test`.`a` trx id 4425 lock_mode X locks gap before rec insert intention
Record lock, heap no 4 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 8000000d; asc     ;;
 1: len 6; hex 000000001140; asc      @;;
 2: len 7; hex b400000128011c; asc     (  ;;

从上面的输出可以看到在记录13上面加了一把插入意图锁(lock_mode X locks gap before rec insert intention)。
获得插入意图锁之后,我们就可以在11-13之间并发插入记录,而不需要一个事物等待另一事物,当所有相关的插入的事物都提交后, 13上的插入意向锁 便会释放。

自增锁(AUTO-INC Locks)

在InnoDB中,每个含有自增列的表都有一个自增长计数器。当对含有自增长计数器的表进行插入时,首先会执行select max(auto_inc_col) from t for update来得到计数器的值,然后再将这个值加1赋予自增长列。我们将这种方式称之为AUTO_INC Lock

AUTO_INC Lock是一种特殊的表锁,它在完成对自增长值插入的SQL语句后立即释放,所以性能会比事务完成后释放锁要高。由于是表级别的锁,所以在并发环境下其依然存在性能问题。

从MySQL 5.1.22开始,InnoDB中提供了一种轻量级互斥量的自增长实现机制,同时InnoDB存储引擎提供了一个参数innodb_autoinc_lock_mode来控制自增长的模式,进而提高自增长值插入的性能。innodb_autoinc_lock_mode和插入类型有关,在介绍它之前,我们先来看看都有哪些插入类型

  • “INSERT-like” statements

    泛指所有的插入语句, 它包括 “simple-inserts”, “bulk-inserts”, 和 “mixed-mode inserts”.

  • “Simple inserts”

    插入的记录行数是确定的:比如:insert into values,replace
    但是不包括: INSERT ... ON DUPLICATE KEY UPDATE.

  • “Bulk inserts”

    插入的记录行数不能马上确定的,比如: INSERT ... SELECT, REPLACE ... SELECT, and LOAD DATA

  • “Mixed-mode inserts”

    这些都是simple-insert,但是部分auto increment值给定或者不给定. 例子如下(where c1 is an AUTO_INCREMENT column of table t1):

    INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');
    

    另外一种 “mixed-mode insert” 就是 INSERT ... ON DUPLICATE KEY UPDATE

介绍完插入类型之后,我们再来看看锁模式,即innodb_autoinc_lock_mode

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

推荐阅读更多精彩内容