tamako tamako
首页
  • Mysql
  • Redis
  • JVM
  • 个人开源项目 (opens new window)
  • 开源官网 (opens new window)
  • B站主页 (opens new window)
  • 摄影
  • 网站
  • 资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

tamako | 玉子

胜人者有力,自胜者强
首页
  • Mysql
  • Redis
  • JVM
  • 个人开源项目 (opens new window)
  • 开源官网 (opens new window)
  • B站主页 (opens new window)
  • 摄影
  • 网站
  • 资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 锁

  • 数据库事务

    • InnoDB RR隔离级别下解决幻读
      • 演示
      • RR隔离级别下解决幻读的原理
      • 发生幻读的场景与原因
      • 总结
  • 日志

  • Mysql
  • 数据库事务
pruedream
2023-12-11
目录

InnoDB RR隔离级别下解决幻读

# InnoDB RR隔离级别下解决幻读

# 演示

A B
begin; begin;
select *from award where id>2;
insert into award (id) values(6);
commit;
select *from award where id>2;
commit;

第一次select

id|award_id|award_type|award_name|award_content|create_time        |update_time        |
--+--------+----------+----------+-------------+-------------------+-------------------+
 3|3       |         1|ipad      |Code         |2021-08-15 15:38:05|2021-08-15 15:38:05|
 4|4       |         1|AirPods   |Code         |2021-08-15 15:38:05|2021-08-15 15:38:05|
 5|5       |         1|Book      |Code         |2021-08-15 15:38:05|2021-08-15 15:38:05|
1
2
3
4
5

第二次select

id|award_id|award_type|award_name|award_content|create_time        |update_time        |
--+--------+----------+----------+-------------+-------------------+-------------------+
 3|3       |         1|ipad      |Code         |2021-08-15 15:38:05|2021-08-15 15:38:05|
 4|4       |         1|AirPods   |Code         |2021-08-15 15:38:05|2021-08-15 15:38:05|
 5|5       |         1|Book      |Code         |2021-08-15 15:38:05|2021-08-15 15:38:05|
1
2
3
4
5
A B
begin ; begin;
select *from award where id>2;
insert into award (id) values(6);
commit;
update award set award_type =2 where id = 6;
select *from award where id>2;
commit;

第一次select

id|award_id|award_type|award_name|award_content|create_time        |update_time        |
--+--------+----------+----------+-------------+-------------------+-------------------+
3|3       |         1|ipad      |Code         |2021-08-15 15:38:05|2021-08-15 15:38:05|
4|4       |         1|AirPods   |Code         |2021-08-15 15:38:05|2021-08-15 15:38:05|
5|5       |         1|Book      |Code         |2021-08-15 15:38:05|2021-08-15 15:38:05|

1
2
3
4
5
6

第二次select

id|award_id|award_type|award_name|award_content|create_time            |update_time            |
--+--------+----------+----------+-------------+-----------------------+-----------------------+
 3|3       |         1|ipad      |Code         |    2021-08-15 15:38:05|    2021-08-15 15:38:05|
 4|4       |         1|AirPods   |Code         |    2021-08-15 15:38:05|    2021-08-15 15:38:05|
 5|5       |         1|Book      |Code         |    2021-08-15 15:38:05|    2021-08-15 15:38:05|
 6|        |         2|          |             |2023-08-18 14:54:19.492|2023-08-18 14:54:19.492|

1
2
3
4
5
6
7

# RR隔离级别下解决幻读的原理

RR 隔离级别下只会出现两种读:当前读,快照读。是不会像读未提交那样不加锁读和不通过MVCC来读历史版本的,其是完全不加锁的读(虽然也只是普通的select,但是rc与rr的普通select就是会通过MVCC来读历史版本(快照读),串行化的普通select都是会自己加锁的(当前读)

  • 针对快照读(普通 select 语句),是通过 MVCC 方式解决了幻读,在快照读的情况下,RR 隔离级别只会在事务开启后的第一次查询生成 Read View ,并使用至事务提交。所以在生成 Read View 之后其它事务所做的更新、插入记录版本对当前事务并不可见,实现了可重复读和防止快照读下的 “幻读”。

  • 针对当前读(select ... for update 等语句),是通过 next-key lock(记录锁+间隙锁)方式解决了幻读,因为当执行 select ... for update 语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。

# 发生幻读的场景与原因

以上两点解决幻读的方式,当前读是没有问题的,因为是加锁读。但是快照读是可能存在幻读发生的的。

  • 针对快照读(普通 select 语句),是通过 MVCC 方式解决了幻读,在可重复读隔离级别下,事务 A 第一次执行普通的 select 语句时生成了一个 ReadView,之后事务 B 向表中新插入了一条 id = 5 的记录并提交。接着,事务 A 对 id = 5 这条记录进行了更新操作,在这个时刻,版本链中会插入这条新记录的历史版本 并且trx_id 隐藏列的值为事务 A 的事务 id,之后事务 A 再使用普通 select 语句去查询这条记录时就可以看到这条记录了(根据可见性算法的读取规则),于是就发生了幻读。

    image-20240227123645750

  • 针对快照读(普通 select 语句),是通过 MVCC 方式解决了幻读,那么如果此时另一个事务跟新了数据,而我们读的时候选择了当前读,就不会去读通过MVCC读版本链,会直接读到跟新的数据。

image-20240227124023046

# 总结

要避免这类特殊场景下发生幻读的现象的话,就是尽量在开启事务之后,马上执行 select ... for update 这类当前读的语句,因为它会对记录加 next-key lock,从而避免其他事务插入一条新记录。

#Mysql
上次更新: 2024/08/09, 16:07:34
MVCC多版本并发控制
Mysql脏页刷盘

← MVCC多版本并发控制 Mysql脏页刷盘→

最近更新
01
骄惰怯
08-10
02
谦虚谦虚谦虚
08-09
03
长期主义
07-17
更多文章>
Theme by Vdoing | Copyright © 2019-2024 tamako | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式