mysql并发读写会产生哪些问题_mysql常见并发场景说明

30次阅读

脏读、不可重复读、幻读分别由事务B未提交更新、已提交更新同一行、已提交插入新行触发;mysql默认RR级通过MVCC+临键锁防前两者,但幻读仅对快照读有效,当前读仍可能发生。

mysql并发读写会产生哪些问题_mysql常见并发场景说明

脏读、不可重复读、幻读到底怎么触发?

这三个问题不是理论概念,而是真实 SQL 执行顺序下必然出现的现象。关键在于:**事务 A 读取时,事务 B 正在做什么、是否已提交、操作的是同一行还是新插入的行**。

  • 脏读:事务 A 执行 select 时,事务 B 刚 UPDATE 了一行但还没 COMMIT;A 读到了这行“未定稿”,B 后续 ROLLBACK → A 的读取结果就失效了。
  • 不可重复读:事务 A 第一次 SELECT id=100 得到 name='Alice';事务 B 提交了 UPDATE users SET name='Bob' WHERE id=100;A 再次 SELECT id=100,得到 name='Bob' —— 同一行值变了。
  • 幻读:事务 A 执行 SELECT * FROM orders WHERE status='pending' 返回 3 条;事务 B 插入一条新 status='pending' 记录并 COMMIT;A 再次执行相同查询,返回 4 条 —— 行数变多了,像“幻影”。注意:这不是更新同一行,而是满足条件的新行被插入。

MySQL 默认的 REPEATABLE READ 真的能防住所有问题吗?

不能。MySQL InnoDB 的默认隔离级别是 REPEATABLE READ,它靠 MVCC + Next-Key Lock(临键锁)实现,能防脏读和不可重复读,但对幻读只做“部分防护”——仅针对普通 SELECT(快照读)有效;一旦用了当前读(如 SELECT ... for UPDATEUPDATEdelete),幻读仍可能发生,尤其在范围条件上。

  • 例如:事务 A 执行 SELECT * FROM t WHERE c > 10 FOR UPDATE 锁住满足条件的记录和间隙;事务 B 尝试插入 c=15 会被阻塞 → 这是幻读被锁挡住。
  • 但如果事务 B 插入的是 c=5(不在 A 的查询范围内),或 A 没加锁直接 SELECT(快照读),那 B 的插入就能成功,A 再查就会“看到幻影”。
  • 真正彻底解决幻读,只有 SERIALIZABLE 隔离级别,但它会让所有并发 SELECT 变成串行,线上基本不用。

写-写冲突:为什么两个 UPDATE 会互相卡住?

当两个事务同时想改同一行,InnoDB 必须用排他锁(X 锁)互斥。谁先拿到锁谁先改,后到的只能等 —— 这就是锁等待。如果等待超时(默认 innodb_lock_wait_timeout = 50 秒),会报错:Lock wait timeout exceeded; try restarting transaction

  • 典型场景:秒杀扣库存,多个请求同时执行 UPDATE goods SET stock = stock - 1 WHERE id = 123 AND stock > 0
  • 陷阱:即使 SQL 带了 AND stock > 0 条件,InnoDB 仍会对匹配的索引记录(甚至间隙)加 X 锁,后续请求必须排队。
  • 优化方向不是“去掉锁”,而是缩短锁持有时间:确保该语句走索引、避免大事务、减少其他无关 SQL 在同一事务中。

读-写并发下,MVCC 是怎么悄悄帮你躲开锁的?

MVCC 不是魔法,它是通过给每行数据维护多个版本(由 DB_TRX_ID 标记),配合事务启动时生成的 ReadView,让普通 SELECT 读取“快照”,而不是最新行 —— 所以读不加锁,也不阻塞写。

  • 关键点:REPEATABLE READ 下,事务第一次 SELECT 生成 ReadView,之后所有快照读都复用它;READ COMMITTED 则每次 SELECT 都新建 ReadView,所以能看到其他事务已提交的修改(即允许不可重复读)。
  • 注意:SELECT ... LOCK IN SHARE MODEFOR UPDATE 是当前读,绕过 MVCC,直接加 S/X 锁,会阻塞其他写操作。
  • 一个易忽略的事实:MVCC 只解决读-写冲突,对写-写冲突完全不管 —— 两个 UPDATE 依然要抢锁,哪怕它们读的是不同快照。

最常被低估的一点:并发问题从来不是孤立存在的。比如你调高了隔离级别防幻读,却没意识到它会让更多语句升级为当前读,从而增加锁竞争;又比如你依赖 MVCC 实现无锁读,却在事务里混进了 SELECT ... FOR UPDATE,瞬间打破快照一致性。真正的并发控制,是隔离级别、锁策略、SQL 写法、应用重试逻辑四者咬合的结果,缺一不可。

text=ZqhQzanResources