数据库的脏读、不可重复读和幻读分别是什么?

在数据库事务管理中,脏读(Dirty Read)、不可重复读(Non-Repeatable Read)和幻读(Phantom Read) 是三种常见的数据一致性问题,通常与 事务隔离级别 相关。


1️⃣ 脏读(Dirty Read)

📌 定义

一个事务读取了另一个未提交事务修改的数据,如果该事务回滚,读取到的数据就会变成无效数据,导致数据不一致。

📌 示例

假设有一个 users 表:

idnamebalance
1Alice1000
🔹 事务 A(未提交)
BEGIN;
UPDATE users SET balance = 500 WHERE id = 1;  -- Alice 余额变为 500
-- 事务 A 还未提交
🔹 事务 B(脏读)
SELECT balance FROM users WHERE id = 1;
-- 事务 B 读取到 balance = 500
🔹 事务 A 回滚
ROLLBACK;
-- 事务 A 撤销修改,balance 恢复到 1000

💥 结果

  • 事务 B 读取到了 balance = 500,但实际上这个值被事务 A 回滚 了,导致读到了无效数据

✅ 解决方案

设置隔离级别 Read Committed(读已提交)或更高,避免读取未提交数据。


2️⃣ 不可重复读(Non-Repeatable Read)

📌 定义

在同一个事务中,两次查询同一行数据,发现第二次查询的数据已经被其他事务修改或删除,导致结果不一致。

📌 示例

假设 users 表:

idnamebalance
1Alice1000
🔹 事务 A
BEGIN;
SELECT balance FROM users WHERE id = 1;
-- 事务 A 读取 balance = 1000
🔹 事务 B(修改数据并提交)
BEGIN;
UPDATE users SET balance = 2000 WHERE id = 1;
COMMIT;
-- 事务 B 修改并提交,Alice 的 balance 变为 2000
🔹 事务 A(再次读取)
SELECT balance FROM users WHERE id = 1;
-- 事务 A 读取到 balance = 2000

💥 结果

  • 同一个事务 A,前后两次读取到的数据不一致(1000 → 2000),发生不可重复读

✅ 解决方案

设置 Repeatable Read(可重复读)隔离级别,事务 A 只能看到事务开始时的数据快照,避免数据被修改。


3️⃣ 幻读(Phantom Read)

📌 定义

在同一个事务中,两次查询同一范围的数据,第二次查询时发现数据“凭空”增加或删除了,但事务没有修改数据。

📌 示例

假设 users 表:

idnamebalance
1Alice1000
2Bob1500
🔹 事务 A
BEGIN;
SELECT COUNT(*) FROM users;
-- 事务 A 读取到 2 条数据
🔹 事务 B(插入新数据并提交)
BEGIN;
INSERT INTO users (id, name, balance) VALUES (3, 'Charlie', 1200);
COMMIT;
-- 事务 B 插入新数据
🔹 事务 A(再次查询)
SELECT COUNT(*) FROM users;
-- 事务 A 读取到 3 条数据

💥 结果

  • 事务 A 在两次查询之间,发现“凭空”多了一条数据(Charlie),发生幻读

✅ 解决方案

使用 Serializable(可串行化)隔离级别,强制所有事务串行执行,避免幻读


📌 对比总结

问题定义示例解决方案
脏读(Dirty Read)读取了未提交事务的数据事务 B 读取到事务 A 未提交的数据,事务 A 回滚后数据失效Read Committed 及以上
不可重复读(Non-Repeatable Read)同一事务多次读取,数据被修改事务 A 两次查询,第一次 balance = 1000,第二次 balance = 2000Repeatable Read 及以上
幻读(Phantom Read)同一事务多次查询,数据行数变化事务 A 查询 COUNT(*),事务 B 插入新数据,事务 A 发现数据变多Serializable 级别

📌 事务隔离级别如何防止这些问题?

隔离级别脏读不可重复读幻读
Read Uncommitted(读未提交)❌ 可能发生❌ 可能发生❌ 可能发生
Read Committed(读已提交)✅ 避免脏读❌ 可能发生❌ 可能发生
Repeatable Read(可重复读,MySQL 默认)✅ 避免脏读✅ 避免不可重复读❌ 可能发生
Serializable(可串行化)✅ 避免脏读✅ 避免不可重复读✅ 避免幻读

✅ 总结

  • 脏读:读取了未提交的数据,可以用 Read Committed 解决。
  • 不可重复读:同一事务多次查询,数据被修改,可以用 Repeatable Read 解决(MySQL 默认)。
  • 幻读:同一事务多次查询,数据数量发生变化,需要 Serializable 解决。

MySQL 默认使用 Repeatable Read,防止了脏读和不可重复读,但仍可能出现幻读。如果要彻底避免幻读,可以使用 Serializable,但会导致性能下降,一般很少使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值