mysql并发问题和隔离级别的梳理

关于—并发问题事务隔离级别InnoDB的实现——这三个概念是数据库理论与实践完美结合的典范。它们之间是**“问题 -> 解决方案 -> 具体实现”**的递进关系。

我们来把这条逻辑链彻底理顺。


1. 源头:并发带来的“三大问题”

当多个事务同时对同一份数据进行读写操作时,如果没有适当的控制,就会导致数据错乱。这种错乱可以归结为三种经典的并发问题:

  • 脏读 (Dirty Read):

    • 场景: 事务A修改了一条数据,但还未提交。事务B此时读取了这条被修改过的“脏”数据。如果事务A最终回滚了,那么事务B读取到的就是一条从未真实存在过的垃圾数据。(ps:未提交是指事务对数据的修改还处于一个临时的、未被最终确认的“草稿”状态,后续可以通过回滚恢复,而提交是一种确定的状态,已确认的状态的修改不称作回滚而是发起新的事务对其的修改,两者与是否写入磁盘无实质性的关系)
    • 比喻: 你看到朋友购物车里加了一件衣服(未付款),你就以为他买了。结果他最后清空了购物车,你的信息就错了。
  • 不可重复读 (Non-Repeatable Read):

    • 场景: 事务A在同一个事务内,先后两次读取同一条数据,但两次读取的结果不同。这是因为在两次读取之间,事务B修改了这条数据并提交了。
    • 比喻: 你第一次查账户余额是1000元。你老婆在另一台手机上给你转了500元并成功到账。你再查一次,发现余额变成了1500元。在你的这次“查询业务”中,数据发生了变化。
    • 重点: 关注的是同一条记录的修改(UPDATE)
  • 幻读 (Phantom Read):

    • 场景: 事务A在同一个事务内,先后两次按相同条件查询一个范围的数据,但两次查询返回的记录行数不同。这是因为在两次查询之间,事务B**插入(INSERT)删除(DELETE)**了符合该条件的新记录。
    • 比喻: 你第一次统计你们部门“所有工资大于1万”的员工,发现有5个人。这时,HR给一个新员工办理了入职,工资是1.2万。你再统计一次,发现变成了6个人,多出来一个像“幻影”一样的员工。
    • 重点: 关注的是一个范围内的记录增减(INSERT/DELETE)

2. 对策:SQL标准定义的“四大隔离级别”

为了解决上述的并发问题,SQL标准委员会定义了四种事务隔离级别(Transaction Isolation Levels)。它们就像四个“安全挡位”,级别越高,数据一致性越好,但并发性能可能会越差。

隔离级别 能解决的问题 可能发生的问题
读未提交 (Read Uncommitted) (几乎没有) 脏读、不可重复读、幻读
读提交 (Read Committed) 解决了脏读 不可重复读、幻读
可重复读 (Repeatable Read) 解决了脏读不可重复读 幻读 (理论上)
串行化 (Serializable) 解决了所有问题 并发性能最差

关系一目了然:

  • 隔离级别就是为了解决并发问题而提出的“解决方案规范”
  • 你想解决什么程度的问题,就选择对应的隔离级别。
  • 比如,大多数数据库(如Oracle, SQL Server)的默认级别是“读提交”,因为它在保证基本数据不错乱(没有脏读)和提供良好并发性能之间取得了很好的平衡。

3. 具体实现:MySQL InnoDB的“独特答卷”

现在,轮到InnoDB出场了。InnoDB作为MySQL的具体实现,它需要遵循SQL标准的这些隔离级别规范,但它可以有自己的独特实现方式

InnoDB的核心武器是MVCC(多版本并发控制),我们之前讨论过。正是MVCC,让InnoDB在实现隔离级别时,表现出了一些非常有趣的特性,特别是对于“可重复读”级别。

  • 读未提交: InnoDB实现它很简单,就是读数据时不加锁,也不用MVCC,直接读最新的。
  • 读提交 (RC): InnoDB通过MVCC实现。每条SELECT语句执行时,都创建一个新的Read View。这保证了只能读到已提交的数据(解决了脏读),但每次读都可能看到不同的已提交数据(有不可重复读问题)。
  • 可重复读 (RR) - 这是InnoDB的默认级别,也是最特别的
    • InnoDB同样通过MVCC实现。只在事务的第一个SELECT语句执行时,创建一个Read View,并一直复用它
    • 神奇之处: 因为Read View被“冻结”在了事务开始的那个时刻,所以它不仅解决了不可重复读(因为你看不到别的事务的UPDATE),在大多数情况下,它也顺便解决了幻读问题! 因为新插入的行,其版本号会比你的Read View要新,所以你也“看不见”它们。
    • 这就是为什么很多人说InnoDB的RR级别“几乎”解决了幻读
    • 例外(什么时候还会幻读?): 当你在RR级别下,先SELECT,然后执行UPDATEINSERT时,可能会触发当前读 (Current Read),绕过MVCC去读取最新版本并加锁,这时就有可能感知到“幻影”的存在。
  • 串行化: InnoDB实现它,就是简单地给所有SELECT语句都隐式地加上LOCK IN SHARE MODE(共享读锁),彻底退回到加锁的模式,强制事务排队。

总结:三者之间的关系

  1. “并发问题”是病症:多个用户同时操作数据库时,可能会导致脏读、不可重复读、幻读等数据不一致的“病症”。

  2. “隔离级别”是药方:SQL标准开出了四种不同强度的“药方”(读未提交、读提交、可重复读、串行化),明确了每种药方能治好哪些病症,以及可能有什么“副作用”(性能损耗)。

  3. “InnoDB的实现”是具体的制药工艺:InnoDB作为一名“制药大师”,它采用了MVCC这种先进的“制药工艺”来生产这些药方。它的工艺非常高超,以至于它生产的“可重复读”这副药,药效超出了标准预期,顺便把幻读这个病也治得七七八八了

所以,它们的关系是:InnoDB通过MVCC机制,实现了SQL标准的四种隔离级别,从而为用户解决了不同程度的并发访问问题。

Author

Cofeesy

Posted on

2025-09-11

Updated on

2025-09-11

Licensed under

Comments