【MySQL篇|第三篇】脏读,幻读,不可重复读

1. 引言

在数据库并发访问场景中,多个事务同时读写同一份数据时,如果没有合理的隔离机制,就可能出现脏读、不可重复读和幻读等问题。理解这三种异常现象及其解决方案,是掌握数据库事务隔离级别的基础。

2. 脏读(Dirty Read)

脏读是指一个事务读取到了另一个事务尚未提交的数据。如果那个事务最终回滚,那么读取到的数据就是"脏"的、不真实的。

举例说明:

  • 事务 A 将某账户余额从 100 元修改为 200 元,但尚未提交。
  • 事务 B 此时读取该账户余额,读到 200 元。
  • 随后事务 A 回滚,余额恢复为 100 元。
  • 事务 B 基于 200 元做出的业务判断就是错误的,这就是脏读。

解决方案 :将隔离级别设置为**读已提交(Read Committed)**或更高,即可避免脏读。读已提交保证事务只能读取到其他事务已提交的数据。

3. 不可重复读(Non-Repeatable Read)

不可重复读是指在一个事务内,两次读取同一行数据,却得到了不同的结果。原因是两次读取之间,该行数据被其他事务修改并提交了。

举例说明:

  • 事务 A 第一次读取某商品价格为 50 元。
  • 事务 B 将该商品价格修改为 80 元并提交。
  • 事务 A 第二次读取同一商品,价格变为 80 元。
  • 事务 A 内两次读取结果不一致,这就是不可重复读。

解决方案 :将隔离级别设置为**可重复读(Repeatable Read)**或更高。可重复读通过行级锁或快照机制,保证事务内多次读取同一行数据结果一致。

4. 幻读(Phantom Read)

幻读是指在一个事务内,两次执行相同的查询 ,第二次却返回了第一次没有出现的行。原因是两次查询之间,其他事务插入了新的数据行并提交。

举例说明:

  • 事务 A 查询价格大于 100 元的商品,返回 3 行。
  • 事务 B 插入一条价格为 150 元的新商品并提交。
  • 事务 A 再次执行相同查询,返回 4 行。
  • 多出来的那一行就像"幻影"一样出现,这就是幻读。

解决方案 :将隔离级别设置为串行化(Serializable) ,或使用**间隙锁(Gap Lock)/ 临键锁(Next-Key Lock)**来锁定查询范围,阻止其他事务在范围内插入新行。

5. 四种隔离级别与问题对照

隔离级别 脏读 不可重复读 幻读
读未提交(Read Uncommitted) 可能 可能 可能
读已提交(Read Committed) 不会 可能 可能
可重复读(Repeatable Read) 不会 不会 可能(MySQL 默认级别下通过间隙锁可避免)
串行化(Serializable) 不会 不会 不会

6. 总结

脏读、不可重复读和幻读是数据库并发控制中的三类典型异常,分别对应未提交数据、已提交行数据变更和新增数据行三种场景。隔离级别越高,并发性能越低,实际生产中应根据业务对数据一致性的要求,在正确性和性能之间做出权衡。

相关推荐
数据库小学妹2 小时前
OLAP数据库怎么选、怎么优化?路线、提速与边界
运维·数据库·后端
织码weavecodes2 小时前
新闻资讯模块设计:内容发布、阅读计数与附件鉴权
java·服务器·数据库
小羊没烦恼!2 小时前
分布式事务 | 使用DTM 的Saga 模式
java·linux·运维·数据库·wpf
这个DBA有点耶2 小时前
备份成功≠数据可恢复:静默损坏会让物理备份把坏页一起带走
数据库·mysql·代码规范
数据库小学妹2 小时前
MySQL MDL锁等待排查:DDL卡住与长事务定位
数据库·后端·mysql
Thneonl3 小时前
ClickHouse UPDATE:一秒返回,三小时才生效
数据库·后端
SelectDB3 小时前
特征导出卡在 JDBC 上,我换成了 Arrow Flight SQL 试试
大数据·数据库·数据分析
一只旭宝3 小时前
【网络精讲6】muduo 的组件与接口:可视化了解muduo库
网络·数据库
泡海椒3 小时前
深度解析JQuick-SQL SQL解析与AST生成机制|分布式SQL原理
数据库·分布式·sql