当前读快照读

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

mysql当前读能取到最新数据吗 mysql什么时候当前读_锁

lock in share mode

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

mysql当前读能取到最新数据吗 mysql什么时候当前读_隔离级别_02

小结

快照读

  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);

mysql当前读能取到最新数据吗 mysql什么时候当前读_事务_03

间隙锁

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

mysql当前读能取到最新数据吗 mysql什么时候当前读_mysql_04

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]
  2. (1,3]
  3. (3,5]
  4. (5,+♾️)


mysql当前读能取到最新数据吗 mysql什么时候当前读_锁_05

意向锁

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

意向锁类型

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

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

意向锁遵循如下协议:

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


mysql当前读能取到最新数据吗 mysql什么时候当前读_mysql当前读能取到最新数据吗_06

兼容性

\

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

锁分类

mysql当前读能取到最新数据吗 mysql什么时候当前读_mysql当前读能取到最新数据吗_07