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 |

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

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

四.场景二(无索引测试)

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

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

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

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

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

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

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

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

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;

同样:

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;

同样:

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.

经验分享 程序员 微信小程序 职场和发展