上一篇 下一篇 分享链接 返回 返回顶部

事务隔离级别详解:脏读幻读与不可重复读

发布人:用户运营 | 723 发布时间:2小时前 阅读量:1

该文章由AI生成,仅为SEO优化测试,相关内容不保证准确!!!

引言

多个事务并发执行时,如果不加控制,会读到“不该读”或“不一致”的数据。SQL 标准定义了四个隔离级别,从宽松到严格逐级解决三类并发异常。理解它们,才能解释“为什么两个用户看到的数据不一样”这类问题。

一、三类并发异常

脏读:事务 A 读到了事务 B 尚未提交的修改——如果 B 回滚,A 读到的数据从未存在过。
不可重复读:事务 A 两次读同一行,中间事务 B 修改并提交了该行,A 两次读到的值不同——针对同一行内容的变更。
幻读:事务 A 按条件查询得到 N 行,中间事务 B 插入了符合条件的新行并提交,A 再查变成 N+1 行——针对结果集行数的变化。

二、四个隔离级别

READ UNCOMMITTED:什么都不防,存在脏读,几乎不用。
READ COMMITTED:解决脏读,但存在不可重复读与幻读。每次读都取最新已提交版本,Oracle/PostgreSQL 默认。
REPEATABLE READ(MySQL 默认):解决脏读与不可重复读——事务开始后首次快照建立,期间多次读同一数据结果一致。InnoDB 通过 MVCC(多版本并发控制)实现:每行数据带版本链,读操作按事务开始时的快照读取,不加锁不阻塞写。
SERIALIZABLE:完全串行化,读也加锁,最安全但并发性能最差。

三、MySQL 的 REPEATABLE READ 与幻读

SQL 标准认为 RR 级别仍可能幻读,但 InnoDB 通过两种机制基本消除了幻读:① 快照读(普通 SELECT)用 MVCC,看到的是事务开始时的快照,新插入的行不可见;② 当前读(SELECT ... FOR UPDATE、UPDATE、DELETE)用间隙锁(Gap Lock)+ 行锁组成的 Next-Key Lock,锁住已存在的行及行间的空隙,阻止其他事务插入新行。因此:普通 SELECT 看不到幻影行;当前读也会被间隙锁挡住。注意一个易混点:RR 事务里先普通 SELECT 再 UPDATE 同一条件,UPDATE 是当前读,会更新到“看不到”的新行——业务上要清楚这两种读的差异。

四、实践建议

绝大多数业务用默认的 REPEATABLE READ 即可;对一致性要求极高的对账、余额扣减,用 SELECT ... FOR UPDATE 显式加锁或乐观锁(version 字段)双保险;长事务是 RR 级别的大敌——快照存在越久,Undo 日志越长,历史链越长导致性能下降,务必控制事务时长。查看当前级别:SELECT @@transaction_isolation;(8.0)或 SELECT @@tx_isolation;(5.7)。

总结

隔离级别的选择就是“一致性 vs 并发性能”的权衡。MySQL 默认 RR 配合 MVCC 与间隙锁已能应对绝大多数场景,重点是避免长事务、理解快照读与当前读的差异,以及对余额类业务显式加锁。

目录结构
全文
微信公众号 微信公众号
抖音官方账号 抖音官方账号
CSDN官方账号 CSDN官方账号
经营主体身份码 经营主体身份码
电子邮箱: admin@2v8.cn

本页面部分展示信息可能存在偏差/错误