InnoDB引擎-行锁算法

InnoDB为锁定一行提供了三种算法
Record Lock:锁定一行
Gap Lock:锁定一个范围,但是不包含当前行
Next_key Lock:锁定一个范围,同时包含当前行
对于Next_Key Lock,如果我们锁定了一个行,如果我们使用的唯一索引(主键就是一个唯一索引)锁定的行,那么这个时候InnoDB会将锁优化成Record Lock,也就是锁定当前行,而不是锁定当前行加一个范围;如果我们使用的不是唯一索引锁定一行数据,那么此时InnoDB就会锁定。Next_Key Lock是为了解决数据库出现幻读的问题。

第一步,创建一个表test,插入数据

mysql> drop table if exists test;
Query OK, 0 rows affected, 1 warning (0.02 sec)

mysql> create table if not exists test(id int primary key,age int(11),name varchar(20),key(age));
Query OK, 0 rows affected (0.44 sec)

mysql> insert into test(id,age,name) values(1,23,'zou');
Query OK, 1 row affected (0.19 sec)

mysql> insert into test(id,age,name) values(2,23,'nan');
Query OK, 1 row affected (0.04 sec)

mysql> insert into test(id,age,name) values(5,32,'fei');
Query OK, 1 row affected (0.04 sec)

mysql> insert into test(id,age,name) values(7,24,'liu');
Query OK, 1 row affected (0.06 sec)

mysql> select *from test;
+----+------+------+
| id | age  | name |
+----+------+------+
|  1 |   23 | zou  |
|  2 |   23 | nan  |
|  5 |   32 | fei  |
|  7 |   24 | liu  |
+----+------+------+

CLIENT A开启事务,并执行一次查询,查询的同时需要加锁

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select *from test where id = 2 for update;
+----+------+------+
| id | age  | name |
+----+------+------+
|  2 |   23 | nan  |
+----+------+------+
1 row in set (0.00 sec)

CLIENT B开启事务,并执行一次插入,

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test(id,age,name) values(4,27,'Li');
Query OK, 1 row affected (0.00 sec)

我们看到,此时事务B执行了一次插入操作,根据我们之前提到的行锁算法Next_Key Lock,我们发现此时的插入操作并没有阻塞,这是因为如果我们是此时是对具有主键(具有唯一索引特性)的索引进行了锁定,那么此时此时锁定的就是一行,而不是锁定一个范围,也就是此时Next_Key Lock会降级为Record Lock。
下面我们来看一个如果我们锁定的是一个非唯一索引,(或者我们压根就没使用索引)
另一个事物执行插入操作会不会出现阻塞的情况。
CLIENT A

mysql> select *from test;
+----+------+------+
| id | age  | name |
+----+------+------+
|  1 |   31 | zou  |
|  2 |   23 | nan  |
|  4 |   27 | Li   |
|  5 |   32 | fei  |
|  7 |   24 | liu  |
+----+------+------+
5 rows in set (0.00 sec)

mysql> start transaction ;
Query OK, 0 rows affected (0.00 sec)

mysql> select *from test where age= 27 for update;
+----+------+------+
| id | age  | name |
+----+------+------+
|  4 |   27 | Li   |
+----+------+------+
1 row in set (0.00 sec)

CLIENT B此时想要插入一个年龄为25和28的数据,我们看一下效果

mysql> insert into test(id,age,name) values(8,25,'qi');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into test(id,age,name) values(3,28,'qi');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

这个时候,我们看到,这个时候事物B发生了阻塞的情况。这是因为当我们在事务A中使用非唯一索引进行查询的时候,这个时候因为查询加锁了,所以InnoDB会使用Next_Key Lock 锁定一个范围是(24,27]以及(27,31)这个范围内的所有的行,同时会使用Record Lock锁定id = 4这个唯一索引这一行。因此当我们要插入的age =25和 28的时候,就会发生这个区间被锁定而出现等待的情况。

mysql> insert into test(id,age,name) values(3,33,'qi');
Query OK, 1 row affected (0.00 sec)

我们看到上面这个插入操作就成功了。因为33不在(24,27]以及(27,31)区间内,索引就不会发生阻塞的情况。

CLIENT A开启事务,并执行一次加锁的查询操作,这个时候我们

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select *from test where age= 27 for update;
+----+------+------+
| id | name | age  |
+----+------+------+
|  4 | Li   |   27 |
+----+------+------+
1 row in set (0.00 sec)

CLIENT B 开启事务,并执行一次插入操作,而且这个插入值是在Next_Key Lock这个区间的

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert test(id,name,age) values(6,'Da',29);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert test(id,name,age) values(6,'Da',33);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

我们发现,这一次好像和Next_Key LOCK没有什么关系了。这是为什么呢?因为Next_Key Lock是对于行的算法,但是对于这个事务A的加锁查询因为没有使用索引,而使用的是扫描整张表,因此这个查询操作并不会使用行锁,而使用的是表锁。

mysql> explain select *from test where age= 27 for update\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6
     filtered: 16.67
        Extra: Using where
1 row in set, 1 warning (0.02 sec)

参考文章

《Mysql技术内幕-InnoDB引擎探析》

你可能感兴趣的:(Mysql)