事务隔离级别需按场景精准选择REPEATABLE READ防不住库存扣减中的幻读SERIALIZABLE性能差READ COMMITTED仍可能触发间隙锁应优先用SELECT ... FOR UPDATE显式加锁并配合唯一约束重试处理幻读。事务隔离级别选错脏读幻读不是bug是配置MySQL 默认的 REPEATABLE READ 看似稳妥但对“库存扣减下单”这类强一致性场景它防不住幻读——比如两个事务同时查到库存 10都通过校验然后都执行 UPDATE inventory SET stock stock - 1结果变成 8 而非预期的 9。这不是代码写错了是隔离级别没压住并发语义。真正起作用的不是“设得高”而是“设得准”READ UNCOMMITTED 基本不用连未提交变更都能读业务逻辑大概率崩READ COMMITTED 能防脏读适合日志归档、报表统计等允许“读到中间态”的场景但在库存类操作中两次 SELECT 可能返回不同结果导致校验失效REPEATABLE READ 是 InnoDB 默认可重复读但幻读靠间隙锁gap lock模拟一不小心就锁表或死锁SERIALIZABLE 最严所有 SELECT 隐式加共享锁写操作阻塞读吞吐暴跌仅适合极低频关键核对如财务对账用 SELECT ... FOR UPDATE 而不是单纯调高隔离级别很多人以为把隔离级别提到 SERIALIZABLE 就万事大吉其实更可靠、更轻量的做法是在关键路径显式加锁。比如扣库存前用 SELECT stock FROM inventory WHERE id 123 FOR UPDATE这条语句会在索引记录上加行锁如果条件走索引后续同 key 的更新必须等待。注意几个实际坑点没走索引FOR UPDATE 会升级为表锁整个表卡住WHERE 条件含函数或隐式转换如 WHERE sku_id 123 但字段是 INT索引失效照样锁全表事务里先 SELECT ... FOR UPDATE再做其他无关查询可能延长锁持有时间增加冲突概率应用层没捕获 Lock wait timeout exceeded 错误直接报 500用户感知就是“下单失败”而非重试幻读真实发生时别硬扛换唯一约束重试比如“防止重复下单”用 SELECT ... FOR UPDATE 查订单是否存在再插入看似闭环但两个事务查完都没单都去插唯一索引冲突后一个失败——这就是幻读在作祟。这时靠隔离级别解决成本高SERIALIZABLE 太重靠锁又难覆盖所有路径。 Murf AI AI文本转语音生成工具