并发事务会造成的四个问题

脏读(Dirty Read)

定义:读到了其他事务未提交的数据

A事务(改,未提交) → B事务(读,读到未提交数据)→A事务(回滚,结束) =B的事务是不存在的数据

  1. T1修改A余额:1000 → 900(未提交

  2. T2读取A余额 → 看到900元

  3. T1突然回滚(比如超时失败)→ A余额恢复为1000元

  4. T2拿着错误的900元做决策 → 系统崩溃!

解决: 🔒 设置隔离级别为 READ_COMMITTED → 只能读到其他事务已提交的数据。

不可重复读(Non-Repeatable Read)

定义:同一事务内,两次读同一数据结果不同(像数据自己会变魔术)

A事务(读,第一次数据)→B事务(改,已提交)→A(读,第二次读) =A事两次数据读内容不一致

  1. T2第一次读A余额 → 1000元

  2. T1提交转账:A余额900元(已提交)

  3. T2第二次读A余额 → 900元

  4. T2懵了:刚才还是1000,现在变900?报表对不上!

解决: 🔒 隔离级别升到 REPEATABLE_READ → 保证事务内多次读取数据值不变(MySQL默认级别)。

幻读(Phantom Read)

定义:同一事务内,两次查询符合条件的记录数不同(像凭空多出幽灵数据)

A事务(读行数,未提交)→B事务(添加了几行,已提交)→A事务(在读,和直接行数不一样) =A一样的条件两次读取行数不一致

  1. T2查询“余额<600的账户数” → 结果1个(只有B账户500元)

  2. T1提交转账:A余额从1000→300(A也满足<600了!

  3. T2再次查询 → 结果变成2个(A和B)

  4. T2怀疑人生:刚才明明是1个!

解决: 🔒 隔离级别升到 SERIALIZABLE(完全串行)或 MySQL用间隙锁(Gap Lock) 锁住查询范围。

💡 不可重复读 vs 幻读核心区别

不可重复读:同一条数据的内容变了(余额从1000→900) 幻读:数据数量变了(多出一条A账户)

脏写(Dirty Write) → 最危险!

定义:两个事务同时修改同一数据,导致修改覆盖(像两人同时编辑文档不保存)

A事务(改,未提交)→B事务(改,未提交)→A事务(提交)→B事务(提交) =A事务提交的数据丢失

  1. T1修改A余额:1000 → 900

  2. T2也修改A余额:1000 → 800(未提交的脏数据上修改!

  3. T1提交 → A=900

  4. T2提交 → A=800(T1的转账被覆盖!钱丢了!

解决: 🔒 所有隔离级别都禁止脏写! 底层用行锁(Row Lock) 保证:修改数据时独占锁定(写锁)。

隔离级别脏读不可重复读幻读脏写
READ_UNCOMMITTED
READ_COMMITTED
REPEATABLE_READ
SERIALIZABLE

✅ = 解决 ❌ = 可能发生

实际项目中的应用

  1. 支付系统:必须用 REPEATABLE_READ → 防止重复扣款(不可重复读)

  2. 库存扣减:需 SERIALIZABLE乐观锁 → 防止超卖(幻读)

  3. 银行核心系统:连读操作也用 SERIALIZABLE → 绝对数据一致性(牺牲性能保安全)

速记口诀

一脏二不可三幻四覆盖

  1. 脏读(读未提交)

  2. 不可重复读(同数据值变)

  3. 幻读(数据量变)

  4. 脏写(覆盖修改)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值