当前位置: 首页 > news >正文

可重复级别下什么情况处理不了幻读

MySQL InnoDB 在 REPEATABLE READ (RR) 隔离级别下,通过 MVCC间隙锁(Next-Key Lock) 在很大程度上避免了幻读,但并非在所有场景下都能 100% 解决。

幻读的核心问题:一个事务在重新执行同一个查询时,看到了第一次查询时没有的新的行(这些行是由其他已提交事务插入的)。

在 RR 级别下,单纯的快照读 (SELECT) 是不会发生幻读的,因为它始终读取事务开始时的快照。幻读通常发生在当前读快照读混合使用的场景中。


无法解决幻读的典型场景举例

让我们来看一个最经典的例子。假设我们有一张表 users

id (主键) name age
1 Alice 20
5 Bob 25
10 Carol 30

事务执行序列如下:

时间点 事务A (Trx ID=50) 事务B (Trx ID=60)
T1 START TRANSACTION;
T2 SELECT * FROM users WHERE age > 20; (快照读)
结果:
id=5, Bob, 25
id=10, Carol, 30
T3 START TRANSACTION;
T4 INSERT INTO users (id, name, age) VALUES (7, 'Dave', 28);
COMMIT; (提交!)
T5 UPDATE users SET name = 'Hi' WHERE age > 20;
InnoDB 报告: “2 rows affected”
T6 SELECT * FROM users WHERE age > 20; (快照读)
结果:
id=5, Hi, 25
id=10, Hi, 30
id=7, Hi, 28 👈 幻读出现了!
T7 COMMIT;

详细过程分析

  1. T2 (事务A - 快照读)

    • 事务A 执行第一次查询 WHERE age > 20
    • InnoDB 为其生成一个 Read View。此时,它只能看到在它开始之前已提交的数据,即 id=5 和 id=10 这两行。
    • 结果符合预期,没有幻读
  2. T4 (事务B - 插入并提交)

    • 事务B 插入了一条新记录 (7, 'Dave', 28),它满足 age > 20 的条件,并且成功提交。这条新数据成为数据库中的最新状态。
  3. T5 (事务A - 当前读)

    • 这是最关键的一步。事务A 执行了一个 UPDATE 语句。
    • UPDATEDELETEINSERT 都属于当前读。它们不是快照读
    • 当执行 UPDATE ... WHERE age > 20 时,InnoDB 必须找到所有当前最新版本中满足 age > 20 的记录以便更新。它会读取最新的已提交数据。
    • 因此,它看到了事务B 刚刚提交的 id=7 这条新记录。
    • InnoDB 会为所有它找到的记录(id=5, 10, 7)加上锁(间隙锁会锁住范围,防止其他事务再插入,但已插入的且已提交的它管不了),然后进行更新。
    • 所以,UPDATE 操作成功更新了3行数据(包括事务B插入的那一行)。UPDATE 操作本身看不到幻读,因为它总是处理最新数据。
  4. T6 (事务A - 快照读)

    • 事务A 再次执行相同的 SELECT 查询。
    • 在 RR 级别下,它依然复用 T2 时刻生成的旧 Read View
    • 但是id=7 这行记录已经被当前事务A自己UPDATE 语句修改了!记住 MVCC 的可见性规则第一条如果数据版本的 DB_TRX_ID 等于当前事务的 ID,则当前事务总是可见的
    • 虽然新插入的 id=7 最初是由事务B (Trx-ID=60) 创建的,但它现在已经被事务A (Trx-ID=50) 修改了。它的 DB_TRX_ID 变成了 50。
    • 因此,对于事务A 来说,这行数据是“我自己修改的”,所以对我可见。
    • 最终,查询结果变成了三条记录。事务A 看到了一个“幻影行”。

为什么说这是幻读?

  1. 第一次读(T2):事务A 看到了 2 行数据。
  2. 中间操作:它试图修改所有满足条件的行。
  3. 第二次读(T6):它发现自己修改了 3 行,并且查询结果也变成了 3 行。

这个“多出来的一行”就是幻读。事务A 的逻辑前提被打破了:它本以为自己在操作 2 行数据,但实际上操作了 3 行。

总结:RR 级别下幻读发生的条件

  1. 并发事务:有两个并发的事务在操作。
  2. 其他事务插入并提交:另一个事务插入了新的行并成功提交
  3. 当前事务进行当前读:当前事务使用了当前读(如 UPDATE, DELETE, SELECT ... FOR UPDATE)来操作一个范围。当前读会看到其他事务已提交的新数据。
  4. 当前事务再次快照读:当前事务随后再次进行快照读时,会因为自己修改了这些新数据(使得其版本号变为自己的事务ID)而看到它们,从而导致幻读。

如何绝对避免幻读?
如果整个事务中的所有操作都使用当前读(例如全部使用 SELECT ... FOR UPDATE),那么由于间隙锁(Gap Lock)和临键锁(Next-Key Lock)的存在,其他事务无法在查询范围内插入新数据,从而可以彻底避免幻读。但这会严重牺牲并发性能。

因此,MySQL InnoDB 的 RR 级别提供的防幻读保障是:纯快照读不会幻读,但当前读可能会引入幻读。如果要实现最高级别的隔离性(序列化),需要应用程序谨慎地使用当前读来手动加锁。

http://www.sczhlp.com/news/52887/

相关文章:

  • 5、设计器-OA的系统登录
  • 当前读和快照读
  • 重庆放心seo整站优化番禺网站开发哪家强
  • 做网站美工未来规划东城网站开发公司
  • 网站建设的总结100字改网站标题
  • 有哪些游戏可以做网站好的企业管理网站
  • 重庆网站制作公司多少钱网络建设合同
  • 做视频网站源码顺德网站建设
  • 杭州模板建站代理three.js 做的网站
  • 做网站 博客wordpress mysql端口
  • 做网站怎么添加关键词深圳seo关键词优化
  • 使用GPT-SoVITS克隆任意角色的声音
  • 0115_建造者模式(Builder)
  • Consul入门--Window
  • 网站配色的原理和方法商城app定制开发
  • Js 手写 Promise 完整实现
  • 网站开发语言排行榜网站改版应该怎么做
  • 用ip的网站要备案吗网络优化软件哪个好
  • 电子商务网站建设首页流程啥是深圳网站定制开发
  • 凡科网站源码下载php 手机网站 模板
  • 内心的冲动和精力的矛盾
  • 20220719_QQ群_KCS1_OAEP模式RSA解密
  • 优化网站做内链接WordPress动画随音乐变化
  • 可以做网站首页的图片素材北京装修公司全包价格
  • 有什么网站可以做试题dedecms公司网站怎么做
  • 正规的国内网站建设公司好的平面设计灵感网站
  • 免费php企业网站wordpress干什么用的
  • 服务器网站建设教程视频教程怎样在网上卖东西步骤
  • metro风格网站模板网站备案信息加到哪里
  • 荣成网站制作公司网站建设的必要性分析