MySQL InnoDB加锁机制下,1-2版本中不同锁类型如何具体分析?
摘要:innoDB的事务,是基于锁来实现的,用到事务不自然就会用到锁,而如果对锁理解的不通透,很容易造成线上问题。 数据库加锁的分析,和事务的引擎,隔离级别,索引,主键索引都有关系, 如果去考虑引擎和各种隔离级别的话,就会很复杂了,所以下面都是基
innoDB的事务,是基于锁来实现的,用到事务不自然就会用到锁,而如果对锁理解的不通透,很容易造成线上问题。
数据库加锁的分析,和事务的引擎,隔离级别,索引,主键索引都有关系,
如果去考虑引擎和各种隔离级别的话,就会很复杂了,所以下面都是基于innoDB和RR的隔离级别进行分析:
表结构:
内容:
1 , 根据主键更新
如果根据主键来行数
事务A
事务B
update user set name='ce1' where id='1';
update user set name='ce3' where Id='3';
同时执行,都成功
update user set name='ce1' where id='1';
update user set name='ce3' where userId='10003';
B更新失败,直至:Lock wait timeout
结论,如果根据非主键来更新,会把整个表进行锁定,无法 进行更新操作。
注:只要是根据主键索引来更新,哪怕事务A没命中主键,也不会锁定整个表
2,根据非索引非主键更新
事务A
事务B
update user set name='ce1' where userId='10001';
update user set name='ce3' where Id='3';
或者
update user set name='ce3' where userId='10003'
都会失败,如果非索引,直接锁表
3, 如果在userId 列上加入普通唯一索引
修改成
再更新
事务A
事务B
update user set name='ce1' where userId='10001';
update user set name='ce3' where Id='3';
或者
update user set name='ce3' where userId='10003'
都会成功,如果有唯一索引,也是能成功行数,互相不影响
4, 如果在userId 列上加入普通非唯一索引 (重点探讨)
把userId改成非唯一索引:
记录内容如下:
+----+--------+------+
| id | userId | name |
+----+--------+------+
| 1 | 10001 | ce1 |
| 2 | 10002 | ce2 |
| 3 | 10001 | ce3 |
| 4 | 10004 | ce4 |
+----+--------+------+
再相同操作
事务A
事务B
update user set name='ce1' where userId='10001';
update user set name='ce3' where Id='3';
B失误执行失败,显然id=3的这行也被锁住了
其实最终还是按主键锁住的记录 id=1和id=3的记录
非唯一索引与普通索引,更一步的区别是GAP锁
gap锁是用于解决幻读的存在,演示
把记录修改成,如:
id为pk. userId为Normal key
A事务
B事务
结果
begin;
update user set name='ce22' where userId='100020';
insert into user (userId,name) values('100021','tttt');
直至事务失败超时
1, 首先GAP锁针对的是insert操作
2, 当更新userId='100020'时,会锁住两边的记录区间,防止幻读的存在。
