并发问题:脏读、不可重复读、幻读

多个事务同时读写同一行时,会出现三类问题:脏读读到别的事务还没提交的修改;不可重复读同一事务内两次读同一行结果不一样(被别的事务改了);幻读同一查询两次返回的行数不同(别的事务插入了新行)。隔离级别就是用来在"正确性"和"并发性能"之间做取舍的档位。

本文核心知识点
  • 脏读读到未提交数据。
  • 不可重复读同行两次读结果不同。
  • 幻读同查询两次行数不同。
  • Next-Key Lock行锁加间隙锁防幻读。
MySQL 锁与隔离级别配图:蓝色渐变背景中央数据库圆柱上压一把发光挂锁,中间一行黄色高亮表格行,左右各一小锁块,扁平科技插画
挂锁压在高亮行上,正是行锁锁住某一行的意象。

四种事务隔离级别

SQL 标准定义四档:读未提交(RU)最低、读已提交(RC)、可重复读(RR)、串行化(Serializable)最高。MySQL InnoDB 默认是 RR。RU 什么问题都不防,RC 防脏读、RR 再防不可重复读,串行化几乎等于全表加锁、并发最差。

行锁与表锁

InnoDB 默认走行锁,只锁涉及的行,并发好。但行锁是加在索引上的:如果更新语句没走索引,它会退化成扫全表、实际上锁住所有行(近似表锁)。所以更新语句一定要带上能命中索引的条件,否则并发能力骤降。

间隙锁与 Next-Key Lock

RR 级别下,InnoDB 用间隙锁(Gap Lock)锁住索引记录之间的"空隙",配合行锁组成 Next-Key Lock,防止别的事务在这个范围里插入新行,从而解决幻读。代价是锁的范围变大、更容易冲突,但在 RR 下这是保证可重复读的关键。