mysql在RR级别下各场景的锁定测试

一.基本信息

版本:10.0.20-MariaDB-log

事务隔离级别: REPEATABLE-READ

innodb_lock_wait_timeout=60

innodb_locks_unsafe_for_binlog=off

innodb_rollback_on_timeout=off 

二. 表信息

CREATE TABLE t1
(
id int unsigned not null auto_increment,
vid int unsigned not null default 0,
name varchar(10) not null default '',
other varchar(20) not null default '',
primary key(id),
key vid(vid)
) engine =InnoDB;

 

Insert into t1 values(1,1,'zengxw1','I am a DBA'),(2,2,'zengxw2','I am a DBA 2');

 

select * from t1;

+----+-----+---------+--------------+

| id | vid | name    | other        |

+----+-----+---------+--------------+

|  1 |   1 | zengxw1 | I am a DBA   |

|  2 |   2 | zengxw2 | I am a DBA 2 |

 

三.场景一(排它锁与共享锁测试)

mysql在RR级别下各场景的锁定测试_第1张图片

因为排它锁与共享锁不兼容,肯定会锁。

 

.场景二(无索引测试)

mysql在RR级别下各场景的锁定测试_第2张图片

因为name字段上没有索引,所以锁会升级为表锁。

 

.场景三(一个条件有索引,一个条件无索引测试)

 mysql在RR级别下各场景的锁定测试_第3张图片

因为vid字段上有索引,都会锁住vid=1对应的记录。

 mysql在RR级别下各场景的锁定测试_第4张图片

因为vid=1vid=2锁定的记录不同。 

 

.场景四(vid为非唯一索引的插入测试一)

 mysql在RR级别下各场景的锁定测试_第5张图片

Session 2同样插入:Insert into t1 values (4,4,'zengxw4','I am a DBA 4')也会锁定,查找原因,是由于表中只有两条记录:vid=1vid=2, session 2update操作,会在表上产生gap

Gap范围为:[1,无穷大),此范围内的值都会锁,也就是上一个值到下一个值之间(同时需要考虑主键)。若vid的值为:1,2,3时,对应主键id分别为:1,2,5,其gap[id任何值,1][2,2]再到[5,3]之间。

一句话vid要小于上一个值,vidid都要大于或等于下一个值才不会锁。

 Select * from t1;

----+-----+---------+--------------+

| id | vid | name    | other        |

+----+-----+---------+--------------+

|  1 |   1 | zengxw1 | I am a DBA   |

|  2 |   2 | ??      | I am a DBA 2 |

|  5 |   3 | ??      | I am a DBA 3 | 

举例来说:

会话1执行:update t1 set name ='??' where vid=2;

会话2执行:

Insert into t1 values (4,3,'zengxw4','I am a DBA 4'); ---会锁

Insert into t1 values (6,3,'zengxw4','I am a DBA 4'); ---不会锁

Insert into t1 values (0,1,'zengxw3','I am a DBA 3'); --会锁

Insert into t1 values (10,1,'zengxw3','I am a DBA 3');--会锁

 

.场景五(b为非唯一索引的插入测试二)

CREATE TABLE tt1( a INT, b INT, PRIMARY KEY (a), KEY(b));

insert into tt1 values(1,1), (3,1), (5,3), (7,6),(10,8);

select * from tt1;

+----+------+

| a  | b    |

+----+------+

|  1 |    1 |

|  3 |    1 |

|  5 |    3 |

|  7 |    6 |

| 10 |    8 |

+----+------+ 

会话一执行:

SELECT* FROM tt1 WHERE b =3 FOR UPDATE;

 mysql在RR级别下各场景的锁定测试_第6张图片

同样:

INSERT INTO tt1 SELECT 6,5; ---会锁

INSERT INTO tt1 SELECT 2,2; ---会锁

INSERT INTO tt1 SELECT 4,6; ---会锁

而INSERT INTO tt1 SELECT 8,6; --不锁

 

.场景六(b为唯一索引的插入测试)

vid改成唯一索引测试:

CREATE TABLE tt2( a INT, b INT, PRIMARY KEY (a), unique KEY(b));

insert into tt2 values(1,1), (3,3), (5,4), (7,7),(10,8);

select * from tt2;

+----+------+

| a  | b    |

+----+------+

|  1 |    1 |

|  3 |    3 |

|  5 |    4 |

|  7 |    7 |

| 10 |    8 | 

会话一执行:

SELECT* FROM tt1 WHERE b =3 FOR UPDATE;

 mysql在RR级别下各场景的锁定测试_第7张图片

同样:

INSERT INTO tt2 SELECT 6,5; ---不锁

INSERT INTO tt2 SELECT 2,2; ---不锁

INSERT INTO tt2 SELECT 4,6; ---不锁

结论:当b为唯一索引时,RR级别下不存在gap锁,只有record锁。

 

总结:

1.  主键索引有record lock

2.  唯一辅助索引有record lock

3.  非唯一辅助索引有next-key lock

4.  没有索引的话,则是全表范围的next-key lock

5.  RC下只有record lock

6.  RR&innodb_locks_unsafe_for_binlog=1,只有record lock.

 

 

你可能感兴趣的:(mysql锁定)