zoukankan      html  css  js  c++  java
  • 使用next-key locks 用于搜索和索引扫描,可以防止幻读

    Next-Key Locks
    
    A next-key lock is a combination of a record lock on the index record and a gap lock on the gap before the index 
    
    record. 
    
    是一个记录锁在索引记录上和一个区间锁在区间的组合 在index record之前
    
    
    
    InnoDB 执行行级锁以这种方式 当它搜索或者扫描一个表的索引,它设置共享或者排它锁在Index records。
    
    因此, row-level locks 实际上是 index-record locks.
    
    
    一个 next-key lock 在一个index record 也会影响 那个index record 记录前的gap
    
    
    也就是说 一个next-key lock 是一个 index-record lock plus a gap lock 
    
    
    If one session has a shared or exclusive lock on record R in an index, another session cannot insert a new index 
    
    record in the gap immediately before R in the index order. 
    
    如果一个session 有一个共享或者排它锁在记录R上,另外的session 不能插入新的index record 在before R这个区间
    
    
    Session 1:
    mysql> start transaction;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> update SmsTest set phoneNo=111 where  phoneNo <10;
    Query OK, 20 rows affected (0.01 sec)
    Rows matched: 20  Changed: 20  Warnings: 0
    
    mysql> explain  update SmsTest set phoneNo=111 where  phoneNo <10;
    +----+-------------+---------+-------+---------------+--------------+---------+-------+------
    
    +------------------------------+
    | id | select_type | table   | type  | possible_keys | key          | key_len | ref   | rows | Extra                  
    
          |
    +----+-------------+---------+-------+---------------+--------------+---------+-------+------
    
    +------------------------------+
    |  1 | SIMPLE      | SmsTest | range | SmsTest_idx1  | SmsTest_idx1 | 4       | const |   20 | Using where; Using 
    
    temporary |
    +----+-------------+---------+-------+---------------+--------------+---------+-------+------
    
    +------------------------------+
    1 row in set (0.00 sec)
    
    
    锁住1-9的记录
    
    
    mysql> select * from SmsTest  where  phoneNo <10;
    +-------+---------+-------------+--------+
    | sn    | phoneNo | channelType | status |
    +-------+---------+-------------+--------+
    |     1 |       1 |           2 |      1 |
    | 45210 |       1 |           1 |      1 |
    | 45211 |       1 |           1 |      1 |
    |     2 |       2 |           2 |      1 |
    |   201 |       2 |           1 |      1 |
    | 45212 |       2 |           1 |      1 |
    |     3 |       3 |           2 |      1 |
    | 45209 |       3 |           1 |      1 |
    | 45213 |       3 |           1 |      1 |
    |     4 |       4 |           2 |      1 |
    | 45214 |       4 |           1 |      1 |
    |     5 |       5 |           2 |      1 |
    | 45215 |       5 |           1 |      1 |
    |     6 |       6 |           2 |      1 |
    | 45216 |       6 |           1 |      1 |
    |     7 |       7 |           2 |      1 |
    | 45217 |       7 |           1 |      1 |
    |     8 |       8 |           2 |      1 |
    | 45218 |       8 |           1 |      1 |
    |     9 |       9 |           2 |      1 |
    +-------+---------+-------------+--------+
    20 rows in set (0.00 sec)
    
    
    Session 2:
    
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(1,1,1); --hang
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(2,1,1);  --hang
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(3,1,1);  --hang
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(4,1,1); --hang
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(5,1,1); --hang
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(6,1,1);  --hang
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(7,1,1); --hang
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(8,1,1); --hang
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(9,1,1); --hang
    
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(10,1,1);
    Query OK, 1 row affected (0.01 sec)
    
    mysql> 
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(11,1,1);
    Query OK, 1 row affected (0.00 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(12,1,1);
    Query OK, 1 row affected (0.01 sec)
    
    
    假设一个Index 包含值10,11,13和20,可能的next-key locks 对于这个索引覆盖下面的区间,
    
    一个圆括号表示排除两端,一个方块号报表包含
    
    (negative infinity, 10] 负无穷大
    (10, 11]
    (11, 13]
    (13, 20]
    (20, positive infinity)正无穷大
    
    
    测试:
    mysql> select * from SmsTest where phoneNo in (10,11,13,20);
    +-------+---------+-------------+--------+
    | sn    | phoneNo | channelType | status |
    +-------+---------+-------------+--------+
    |    10 |      10 |           2 |      1 |
    | 45239 |      10 |           1 |      1 |
    | 45252 |      10 |           1 |      1 |
    |    11 |      11 |           2 |      1 |
    | 45253 |      11 |           1 |      1 |
    |    13 |      13 |           2 |      1 |
    |    20 |      20 |           2 |      1 |
    +-------+---------+-------------+--------+
    7 rows in set (0.00 sec)
    
    
    
    mysql> update SmsTest set phoneNo=999 where  phoneNo in (10,11,13,20);
    Query OK, 7 rows affected (0.00 sec)
    Rows matched: 7  Changed: 7  Warnings: 0
    
    mysql> explain update SmsTest set phoneNo=999 where  phoneNo in (10,11,13,20);
    +----+-------------+---------+-------+---------------+--------------+---------+-------+------
    
    +------------------------------+
    | id | select_type | table   | type  | possible_keys | key          | key_len | ref   | rows | Extra                  
    
          |
    +----+-------------+---------+-------+---------------+--------------+---------+-------+------
    
    +------------------------------+
    |  1 | SIMPLE      | SmsTest | range | SmsTest_idx1  | SmsTest_idx1 | 4       | const |    7 | Using where; Using 
    
    temporary |
    +----+-------------+---------+-------+---------------+--------------+---------+-------+------
    
    +------------------------------+
    1 row in set (0.00 sec)
    
    
    
    Session 2:
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(1,1,1);
    Query OK, 1 row affected (0.01 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(2,1,1);
    Query OK, 1 row affected (0.00 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(3,1,1);
    Query OK, 1 row affected (0.05 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(4,1,1);
    Query OK, 1 row affected (0.01 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(5,1,1);
    Query OK, 1 row affected (0.00 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(6,1,1);
    Query OK, 1 row affected (0.00 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(7,1,1);
    Query OK, 1 row affected (0.01 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(8,1,1);
    Query OK, 1 row affected (0.00 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(9,1,1); --hang
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(10,1,1);--hang
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(11,1,1); --hang
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(12,1,1); --hang
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(13,1,1);--hang
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(14,1,1);
    Query OK, 1 row affected (0.01 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(15,1,1);
    Query OK, 1 row affected (0.00 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(16,1,1);
    Query OK, 1 row affected (0.00 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(17,1,1);
    Query OK, 1 row affected (0.00 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(18,1,1);
    Query OK, 1 row affected (0.00 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(19,1,1);
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(20,1,1); --hang
    
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(21,1,1);
    Query OK, 1 row affected (0.01 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(22,1,1);
    Query OK, 1 row affected (0.00 sec)
    
    mysql>  insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(23,1,1);
    Query1 row   affected (0.01 sec)
    
    默认情况下,InnoDB 操作在 REPEATABLE READ transaction isolation level  禁用innodb_locks_unsafe_for_binlog system 
    
    variable 
    
    在这种情况下,使用next-key locks 用于搜索和索引扫描,可以防止幻读

  • 相关阅读:
    《Microsoft Sql server 2008 Internals》读书笔记第十一章DBCC Internals(2)
    《Microsoft Sql server 2008 Internals》读书笔记第十一章DBCC Internals(9)
    《Microsoft Sql server 2008 Internals》读书笔记第九章Plan Caching and Recompilation(10)
    CKEditor在asp.net环境下的使用一例
    《Microsoft Sql server 2008 Internals》读书笔记第五章Table(7)
    《Microsoft Sql server 2008 Internals》读书笔记第九章Plan Caching and Recompilation(11)
    千万数据的连续ID表,快速读取其中指定的某1000条数据?
    javascript中的float运算精度
    .Net与Java的互操作(.NET StockTrader微软官方示例应用程序)
    《Microsoft Sql server 2008 Internals》读书笔记第十一章DBCC Internals(6)
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13350135.html
Copyright © 2011-2022 走看看