场景
在MySQL-innodb引擎的RR(REPEATABLE-READ)隔离级别下。
当update t set a_column=99 where name=‘张三’;
如果name字段上没有索引,那么行锁将上升为表锁。
重点来了
这句话中,行锁将上升为表锁
- 正确理解:单行锁将上升为全部行锁(即全表锁)。
- 错误理解:行级锁将上升为表级锁。
你品,你细细品
MySQL-innodb引擎加锁原理
这里就不赘述什么共享锁、排查锁、记录锁、间隙锁等等了。主要是说明两点
1、innodb引擎加行锁都是加在索引上的。也很好理解,因为查询也是通过索引,或索引回表来的,行锁当然也是加在索引上的。
2、为什么where的字段没有索引就会从行锁上升为“表锁”,因为没有索引的时候会进行全表扫描,然后把每一个聚簇索引(或隐藏的聚集索引)都锁住。
实验
CREATE TABLE
t
(
id
int(11) NOT NULL AUTO_INCREMENT,
name
varchar(255) DEFAULT NULL,
age
int(11) DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
数据:
1 张三 11
2 李四 12
3 王五 13
隔离级别RR
实验一:
- name字段没有索引
- 会话1:update t set age=111 where name=‘张三’;
- 会话2:update t set age=112 where name=‘李四’;
- 会话3:lock tables t write或lock tables t read;
结论:
- 由于name字段没有索引,行锁上升为表锁,所以会话2无法提交,会话3也无法提交。
- 查看是否有表锁:无表锁
实验二
- name字段有索引
- 会话1:update t set age=111 where name=‘张三’;
- 会话2:update t set age=112 where name=‘李四’;
- 会话3:lock tables t write或lock tables t read;
结论:
- name字段有索引,所以会话2正常提交,会话3依旧无法提交
- 查看是否有表锁:无表锁
实验三
- name字段有索引
- 会话1:lock tables t write或lock tables t read;
- 会话2:update t set age=111 where name=‘张三’;
结论:
- t表被锁表,所以会话2无法提交
- 查看是否有表锁:有表锁
实验四
- name字段有索引
- 会话1:lock tables t write或lock tables t read;
- 会话2:select * from t;
结论:
- t表被锁定读时,会话2可以查到数据
- t表被锁定写时,会话2不能查到数据
- 查看是否有表锁:有表锁
如果还是理解不了,再次附上锁的兼容关系图,跟着实验再走一遍就好了
最后最后
不要再把“如果xxx字段上没有索引,那么行锁将上升为表锁”中的表锁理解为表级锁了!
表级锁和全表锁的实现方式是完全不同的!