• 对于唯一索引使用唯一条件搜索, InnoDB 只锁定找到的index record,不是它之前的区间


    | test100 | CREATE TABLE `test100` (
      `sn` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增编号',
      `phoneNo` int(11) DEFAULT NULL,
      `channelType` int(11) DEFAULT NULL COMMENT '通道识别',
      `status` tinyint(4) NOT NULL COMMENT '短信转态,1.发送成功,2.发送失败,3.发送异常',
      PRIMARY KEY (`sn`),
      UNIQUE KEY `test100_idx1` (`phoneNo`)
    
    
    Session 1:
    
    mysql>  select * from test100  where phoneNo between 10 and 20 for update;
    +----+---------+-------------+--------+
    | sn | phoneNo | channelType | status |
    +----+---------+-------------+--------+
    | 10 |      10 |           2 |      1 |
    | 11 |      11 |           2 |      1 |
    | 16 |      16 |           2 |      1 |
    | 17 |      17 |           2 |      1 |
    | 18 |      18 |           2 |      1 |
    | 19 |      19 |           2 |      1 |
    | 20 |      20 |           2 |      1 |
    +----+---------+-------------+--------+
    7 rows in set (0.00 sec)
    
    mysql> rollback;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> start transaction;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select * from test100 where phoneNo=16 for update;
    +----+---------+-------------+--------+
    | sn | phoneNo | channelType | status |
    +----+---------+-------------+--------+
    | 16 |      16 |           2 |      1 |
    +----+---------+-------------+--------+
    1 row in set (0.00 sec)
    
    
    Session 2:
    
    mysql> insert into zjzc.test100(PhoneNo,channelType,status)  values(15,1,1);
    Query OK, 1 row affected (0.01 sec)
    
    mysql> insert into zjzc.test100(PhoneNo,channelType,status)  values(14,1,1);
    Query OK, 1 row affected (0.01 sec)
    
    mysql> insert into zjzc.test100(PhoneNo,channelType,status)  values(17,1,1);
    ERROR 1062 (23000): Duplicate entry '17' for key 'test100_idx1'
    mysql> 
    
    
    此时RR模式下唯一索引 可以插入
    
    /****************************************************************
    mysql> select * from test100 where phoneNo<20;
    +----+---------+-------------+--------+
    | sn | phoneNo | channelType | status |
    +----+---------+-------------+--------+
    |  1 |       1 |           2 |      1 |
    |  2 |       2 |           2 |      1 |
    |  3 |       3 |           2 |      1 |
    |  4 |       4 |           2 |      1 |
    |  5 |       5 |           2 |      1 |
    |  6 |       6 |           2 |      1 |
    |  7 |       7 |           2 |      1 |
    |  8 |       8 |           2 |      1 |
    |  9 |       9 |           2 |      1 |
    | 10 |      10 |           2 |      1 |
    | 11 |      11 |           2 |      1 |
    | 16 |      16 |           2 |      1 |
    | 17 |      17 |           2 |      1 |
    | 18 |      18 |           2 |      1 |
    | 19 |      19 |           2 |      1 |
    +----+---------+-------------+--------+
    15 rows in set (0.00 sec)
    
    测试非唯一索引情况下:
    
    | test100 | CREATE TABLE `test100` (
      `sn` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增编号',
      `phoneNo` int(11) DEFAULT NULL,
      `channelType` int(11) DEFAULT NULL COMMENT '通道识别',
      `status` tinyint(4) NOT NULL COMMENT '短信转态,1.发送成功,2.发送失败,3.发送异常',
      PRIMARY KEY (`sn`),
      KEY `test100_idx1` (`phoneNo`)
    ) ENGINE=InnoDB AUTO_INCREMENT=5023 DEFAULT CHARSET=utf8 COMMENT='短信发送成功记录表'  
    
    
    
    Session 1:
    mysql> start transaction;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select * from test100 where phoneNo=16 for update;
    +----+---------+-------------+--------+
    | sn | phoneNo | channelType | status |
    +----+---------+-------------+--------+
    | 16 |      16 |           2 |      1 |
    +----+---------+-------------+--------+
    1 row in set (0.00 sec)
    
    Session 2:
    mysql> insert into zjzc.test100(PhoneNo,channelType,status)  values(14,1,1); --hang
    
    mysql> insert into zjzc.test100(PhoneNo,channelType,status)  values(13,1,1); -hang
    
    mysql> insert into zjzc.test100(PhoneNo,channelType,status)  values(15,1,1); -hang
    
    mysql> insert into zjzc.test100(PhoneNo,channelType,status)  values(16,1,1); -hang
    mysql> insert into zjzc.test100(PhoneNo,channelType,status)  values(17,1,1);
    Query OK, 1 row affected (0.01 sec)
    
    
    结论:
    
    For a unique index with a unique search condition, InnoDB locks only the index record found, not the gap before it.
    
    对于唯一索引使用唯一条件搜索, InnoDB 只锁定找到的index record,不是它之前的区间
    
    For other search conditions, InnoDB locks the index range scanned, using gap locks or next-key locks to block 
    
    insertions by other sessions into the gaps covered by the range. 
    
    
    对于其他搜索条件, InnoDB 扫描的索引范围,使用gap lock  or next-key locks 来堵塞其他会话插入这个区间
    
    
    
    区间锁:
    
    一个区间锁 是一个锁在index记录之间的区间,或者一个锁在第一个或者最后一个index记录的区间
    
    比如,SELECT c1 FOR UPDATE FROM t WHERE c1 BETWEEN 10 and 20;  
    
    
    组织其他事务插入值为15到t.c1列,不管是否这里已经有这些的值存储,
    
    
    因为区间锁是在所有存在的值在这个范围被锁定
    
    一个区间锁扩约一个单独的索引值,多个索引值,甚至是空的
    
    区间锁是权衡并发和性能的一部分, 用于一些事务隔离而不是其他
    
    
    Gap 锁定不能用于语句 ,锁定记录使用一个unique index来搜索用于一个唯一的记录
    
    (这个不能包含例子 搜索条件只包含多列唯一索引的一些列,在那种情况下,gap locking 也存在)
    
    比如, 如果Id列有一个唯一索引,下面语句只用一个index-record锁用于记录id值为100 
    
    它不管是否其他灰灰插入记录到前面的区间
    
    SELECT * FROM child WHERE id = 100;
    
    如果id没有被索引或者有一个非唯一索引,语句会锁前面的区间
    
    
    
    在InnoDB中Gap locks 是"纯粹抑制的", 这意味着它们只能停止其他事务防止插入到这个区间。
    
    它们不阻止不同的事务来利用区间锁在相同的区间
    
    区间锁可以被显示禁用, 这个发生如果你改变的事务隔离为 READ COMMITTED
    
    或者启用了innodb_locks_unsafe_for_binlog 
    
    
    在这群情况下, 区间锁是被禁用的用于搜索和索引扫描
    
    

  • 相关阅读:
    根据浏览器是否出现滚动条,显示返回顶部
    HTML5 屏蔽触屏滚动
    url参数中带有+号,服务器端解码之后没了
    jQuery1.9之后使用on()绑定 动态生成元素的 事件无效
    列表页复选框全选效果
    Python安装sqlite3
    python3.5中,import sqlite3 出现 no module named _sqlite3的解决方法
    使用js设置input标签只读 readonly 属性
    怎么获得当前点击的按钮的id名?
    JS 浮点型数字运算(转)
  • 原文地址:https://www.cnblogs.com/zhaoyangjian724/p/6199079.html
Copyright © 2020-2023  润新知