mysql锁与当前读快照读

129 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

当前读快照读

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”,“当前读” 1

lock in share mode

RR隔离级别下,加共享锁也是“当前读” 2

小结

快照读

  1. 普通select

当前读

  1. select for update
  2. lock in share mode
  3. insert涉及的普通select,例如:(insert user_a select * from user_b;)
  4. update,同insert
  5. delete,同insert

mysql锁

锁类型

  1. 行锁(record lock)
  2. 间隙锁(gap lock)
  3. next-key锁
  4. 意向锁(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);3

间隙锁

称其为范围锁感觉更佳合适些,不仅仅锁指定的行,还会锁行范围之间行(包含表中范围内不存在的行),例如: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;

4

next-key锁

官方描述:next-key锁=行锁+间隙锁 dev.mysql.com/doc/refman/… 个人认为其实就是间隙锁的特例,间隙锁会额外锁住下一个范围,上一段落的间隙锁案例中不仅锁住了extend_id范围(1-3),还锁住了extend_id(3-5) ​

user表索引extend_id间隙锁范围分段

  1. (-♾️,1]
  2. (1,3]
  3. (3,5]
  4. (5,+♾️)

5

意向锁

意向锁是表级锁,主要解决表锁性能问题,当一个事务请求表锁时,需要检索表中是否存在排他锁共享锁,因为行锁场景,需要扫描数据检查是否存在行锁,性能很差。意向锁是记录表中是否存在锁,意向锁不记录锁详情,仅记录当前是否存在排他锁或共享锁,因此在申请表锁时仅需要判断是否存在意向锁即可,不需要再扫描表记录。可以大幅度提升表锁性能 ​

意向锁类型

  1. IS 共享意向锁
  2. IX 排他意向锁

当事务申请一行或范围排他锁时,此时表上存在两把锁,一把排他锁,一把排他意向锁。共享意向锁同理 例如: SELECT ... FOR SHARE sets an IS lock, and SELECT ... FOR UPDATE sets an IX lock. ​

意向锁遵循如下协议:

  1. 事务在获取表中某一行上的共享锁之前,必须首先获取表上的IS锁或更强的锁。
  2. 在事务获得表中某一行上的独占锁之前,它必须首先获得表上的IX锁。

6

兼容性

\XIXSIS
XConflictConflictConflictConflict
IXConflictCompatibleConflictCompatible
SConflictConflictCompatibleCompatible
ISConflictCompatibleCompatibleCompatible

mysql锁监控

dev.mysql.com/doc/refman/…

SHOW ENGINE INNODB STATUS
SHOW ENGINE INNODB MUTEX
SHOW ENGINE PERFORMANCE_SCHEMA STATUS

锁分类

7