当前读快照读
mysql事务隔离级别为:read committed,此时默认的查询为“当前读”,即可以读取最新提交的数据
mysql事务隔离级别为:repeatable read(简称RR),此时默认的查询为“快照读”,即近读取事物开启时那个时刻的数据快照
那么RR隔离级别的读是否可以变更为当前读呢?当然时可以的,那么如何实现呢?
select for update
案例数据
mysql> select * from user;
+----+-----------+-----------+
| id | name | extend_id |
+----+-----------+-----------+
| 1 | haha | 2 |
| 2 | spiderman | 1 |
| 3 | NULL | 2 |
| 4 | NULL | 3 |
| 5 | superman | 5 |
+----+-----------+-----------+
5 rows in set (0.00 sec)
session1:开启事务,并查询主键为1的数据
mysql> begin;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from user where id=1;
+----+------+-----------+
| id | name | extend_id |
+----+------+-----------+
| 1 | haha | 2 |
+----+------+-----------+
1 row in set (0.00 sec)
session2:更新主键为1的数据name为“555”
mysql> update user set name='555' where id=1;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1 Changed: 1 Warnings: 0
session1:再次查询主键为1的数据,结果仍为“haha”,快照读。使用select for update查询数据,结果为“555”,“当前读”
lock in share mode
RR隔离级别下,加共享锁也是“当前读”
小结
快照读
- 普通select
当前读
- select for update
- lock in share mode
- insert涉及的普通select,例如:(insert user_a select * from user_b;)
- update,同insert
- delete,同insert
mysql锁
锁类型
- 行锁(record lock)
- 间隙锁(gap lock)
- next-key锁
- 意向锁(intention lock)
案例数据user表
+----+-----------+-----------+
| id | name | extend_id |
+----+-----------+-----------+
| 1 | 555 | 1 |
| 2 | spiderman | 1 |
| 3 | spiderman | 1 |
| 4 | spiderman | 3 |
| 5 | superman | 5 |
+----+-----------+-----------+
行锁
顾名思义,仅锁指定的行,例如:update user set name=‘xixi’ where extend_id = 1。那么仅会锁定extend_id=1的数据,如果插入extend_id为1是可以执行成功,例如:insert into user value (6,‘haha’,1);
间隙锁
称其为范围锁感觉更佳合适些,不仅仅锁指定的行,还会锁行范围之间行(包含表中范围内不存在的行),例如:update user set name=‘xixi’ where extend_id between 1 and 3。不仅仅锁住表中存在的extend_id=1,3的数据,还锁住了表中不存在的extend_id=2的数据,因此插入extend_id=2的数据会阻塞
对于unique index检索唯一的行不会使用间隙锁,例如:
SELECT * FROM user WHERE id = 1;
next-key锁
官方描述:next-key锁=行锁+间隙锁
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html#innodb-record-locks 个人认为其实就是间隙锁的特例,间隙锁会额外锁住下一个范围,上一段落的间隙锁案例中不仅锁住了extend_id范围(1-3),还锁住了extend_id(3-5)
user表索引extend_id间隙锁范围分段
- (-♾️,1]
- (1,3]
- (3,5]
- (5,+♾️)
意向锁
意向锁是表级锁,主要解决表锁性能问题,当一个事务请求表锁时,需要检索表中是否存在排他锁共享锁,因为行锁场景,需要扫描数据检查是否存在行锁,性能很差。意向锁是记录表中是否存在锁,意向锁不记录锁详情,仅记录当前是否存在排他锁或共享锁,因此在申请表锁时仅需要判断是否存在意向锁即可,不需要再扫描表记录。可以大幅度提升表锁性能
意向锁类型
- IS 共享意向锁
- IX 排他意向锁
当事务申请一行或范围排他锁时,此时表上存在两把锁,一把排他锁,一把排他意向锁。共享意向锁同理
例如: SELECT … FOR SHARE sets an IS lock, and SELECT … FOR UPDATE sets an IX lock.
意向锁遵循如下协议:
- 事务在获取表中某一行上的共享锁之前,必须首先获取表上的IS锁或更强的锁。
- 在事务获得表中某一行上的独占锁之前,它必须首先获得表上的IX锁。
兼容性
\ | X | IX | S | IS |
X | Conflict | Conflict | Conflict | Conflict |
IX | Conflict | Compatible | Conflict | Compatible |
S | Conflict | Conflict | Compatible | Compatible |
IS | Conflict | Compatible | Compatible | Compatible |
mysql锁监控
https://dev.mysql.com/doc/refman/8.0/en/show-engine.html
SHOW ENGINE INNODB STATUS
SHOW ENGINE INNODB MUTEX
SHOW ENGINE PERFORMANCE_SCHEMA STATUS
锁分类