百度分公司 网站外包,推荐几个没封的网站,做交易网站什么开发语言,做一个购物网站价格测试环境及相关必要知识
测试环境为mysql 8 版本
间隙锁#xff08;Gap Lock#xff09;#xff1a;用于锁定索引范围之间的间隙#xff0c;防止其他事务在此间隙中插入新记录。间隙锁主要用于防止幻读问题。
在可重复读的隔离级别下默认打开该锁机制#xff0c;解决幻…测试环境及相关必要知识
测试环境为mysql 8 版本
间隙锁Gap Lock用于锁定索引范围之间的间隙防止其他事务在此间隙中插入新记录。间隙锁主要用于防止幻读问题。
在可重复读的隔离级别下默认打开该锁机制解决幻读问题也可手动修改配置文件关闭该锁机制该锁机制为innodb自动决定间隙范围上锁无需SQL显式声明锁。
表结构如下 数据如下 Mysql 运行中事务可以在表 information_schema.INNODB_TRX 中查看
Mysql 运行中事务持有的锁可以在表 performance_schema.data_locks 中查看 一行分割两张图了
Mysql 运行中事务等待持有锁的事务可以在表 performance_schema.data_lock_waits 中查看
LOCK MODE锁模式将出现的锁模式值和解释
S共享锁Shared Lock允许其他事务获取相同对象的共享锁但不允许排它锁。 X排它锁Exclusive Lock在事务持有排它锁期间其他事务无法获取相同对象的共享锁或排它锁。 IS意向共享锁Intention Shared Lock表示事务准备获取一个表中某些行的共享锁。 IX意向排它锁Intention Exclusive Lock表示事务准备获取一个表中某些行的排它锁。 SIX共享意向排它锁Shared Intention Exclusive Lock表示事务准备获取一个表中某些行的共享锁但也准备获取这些行的排它锁。 REC_NOT_GAP是MySQL InnoDB存储引擎中的一个特殊锁模式用于锁定记录行而非间隙gap
注意接下来将看到很多意向锁意向排他锁并不等于持有了排它锁只是表明有持有该锁的意向 LOCK TYPE(锁类型)可能出现的是RECORD 行锁、TABLE表锁 下面的各种情况下MySQL InnoDB锁持有情况的结构是先展示SQL后展示持有锁的截图 持有锁截图中重要的字段为INDEX_NAME 索引名 LOCK_TYPE 锁类型 LOCK_MODE 锁模式 LOCK_STATUS 锁状态 LOCK_DATA 锁数据 走唯一索引的主键id指定值有值情况
begin ;
select * from t_gap_demo where id 3 for update ;结果对id3的行记录上了行排他锁当前表的意向排他锁
走唯一索引的主键id指定值无值情况
begin ;
select * from t_gap_demo where id 4 for update ;插入id4数据被阻塞证明(3,]间隙已被锁定插入id8数据成功插入id2数据成功 结果对数据7持有了排他锁、间隙锁范围为(3,7] 左开右闭原则
走唯一索引的主键id指定范围有值情况
begin ;
select * from t_gap_demo where id between 3 and 8 for update ;结果持有了主键索引上的1、3、7、15四行的行锁且无间隙锁持有表排它锁意向锁额外还持有了普通索引age上的所有值的排它锁及间隙锁0到正无穷都锁住了这个字段没有负数 这个结果挺让人震惊的这句SQL居然持有了这么多锁而且我测试插入id2,age1的记录是无法插入的一直被阻塞。证明age整个范围的间隙锁都是被锁住了的无法插入任何数据。 额外我还测试了一下该情况下update语句的锁情况
begin ;
update t_gap_demo set age 1 where id between 3 and 8 ;结果是锁住了(3,7] (7,15]间隙锁3、7、15行锁附带基本的表排他锁意向锁至于为啥select语句时锁住了整个age间隙还需要后续研究有懂的大佬评论一下
走唯一索引的主键id指定范围无值情况
begin ;
select * from t_gap_demo where id between 18 and 28 for update ;id 14可以插入id 16无法插入阻塞 结果持有了排它锁锁住最后一行记录15到正无穷
begin ;
select * from t_gap_demo where id between 10 and 12 for update ;于是我又好奇假设这个区间无值但是属于某个间隙呢 结果持有了这个范围所在间隙的间隙锁 (7,15]15这个行记录的排它锁表意向排它锁
走普通索引的age指定值有值情况
begin ;
select * from t_gap_demo where age 3 for update ;结果主键id1的记录行锁排它锁锁定、普通索引上3,1 6,3全部锁定行记录加间隙表意向排它锁
走普通索引的age指定值无值情况
begin ;
select * from t_gap_demo where age 4 for update ;结果持有了这个不存在的id处于的这个间隙的间隙锁和两个行记录的排它锁表意向排它锁
走普通索引的age指定范围有值情况
begin ;
select * from t_gap_demo where age between 20 and 40 for update ;结果持有了整个范围涉及的间隙的间隙锁、涉及行的排他锁涉及行记录的主键记录的排它锁不带间隙锁表意向排它锁
走普通索引的age指定范围无值情况
begin ;
select * from t_gap_demo where age between 78 and 88 for update ;结果持有age记录最大值到正无穷的间隙锁表意向排它锁
拓展非索引字段范围锁定
begin ;
select * from t_gap_demo where age between 1 and 15 for update ;结果持有了整个id范围内所有行记录的排它锁和所在区间包括左右无穷的间隙锁尝试插入id2id16记录都是阻塞状态
总结
经过各种情况下事务对数据的加排它锁测试发现mysql 8 innodb引擎会对涉及的数据和间隙都加上排他、间隙锁甚至在普通索引时还会对涉及数据的主键索引也加上不带间隙锁的排它锁X,REC_NOT_GAP在非索引字段范围锁定时会对整个数据和间隙锁定这告诉我们在使用时要注意追求性能时少使用悲观锁尽量避免锁竞争、避免死锁尽量走主键索引或索引、尽量少锁定资源或只锁定最小范围数据、尽量精确操作某行数据尽量让事务执行时间短尽量避免同时事务并发操作同间隙内数据以避免死锁。