写点什么

Mysql 的事务隔离与实现

发布于: 2021 年 05 月 07 日

本文讨论只针对 mysql 的 innodb 存储引擎。因为只有 innodb 支持事务,所谓事务隔离必须支持事务才有讨论的意义。


1. 为什么需要需要隔离?

主要是为了解决以下三类问题:脏读、不可重复读、幻读

  • 脏读:一个事务可以读取到其他事务未提交的数据

  • 不可重复读:事务 A 在其执行过程中,针对一条数据的两次 select 获取到的值不一致。通常是因为其他事务在事务 A 执行过程中,更新了数据并提交导致

  • 幻读:幻读是针对数据插入场景,指的是事务 A 在执行过程中,针对某条数据 a 已经更新为 b,但此时有其他事务再一次插入与 a 一摸一样的数据,事务 A 再次 select 会再次读到数据 a,感觉像是之前的更新未起效果,出现幻觉


2. 事务隔离级别?

事务隔离级别分为 4 个层次,性能依次递减,隔离强度递增:读未提交、读提交、可重复读、串行化。

  • mysql 默认隔离级别是可重复读,其他则默认是读已提交

  • mysql 在可重复读级别解决了幻读的问题(行锁+间隙锁)


3. 事务隔离的实现?

  • 读未提交:可以理解为没有什么隔离效果,不需要特殊实现,未加锁

  • 串行化:读时加共享锁,此时其他事务只能读不能写;写时加排他锁,此时其他事务不可读,不可写,事务的执行变成串行

  • 读已提交 &可重复读:innodb 采用 mvcc 方式实现可重复读。即每条记录有一个版本链,版本链上每个 row 包含了一个 trx_id 字段,记录产出当前版本数据的事务 id。读已提交和可重复读的不同在于生成快照时机的不一致(读写操作是基于当前快照进行操作的)。所谓快照满足以下条件:

  • 当前事务内更新,可以读到

  • 版本未提交,不能读到

  • 版本已提交,但是在快照创建后提交,不能读到

  • 版本已提交,在快照创建之前提交,可以读到。

所以,可重复读在事务开始阶段创建快照,则事务执行过程中无论其他事务如何更新数据,读的是自己的快照;读已提交,在每次执行 sql 时都创建一次快照,因此只能保证不读到未提交数据,一旦已提交,则可以读到,不保证可重复读。


发布于: 2021 年 05 月 07 日阅读数: 22
用户头像

努力搬砖的编码小菜 2020.09.01 加入

bat搬砖中

评论

发布
暂无评论
Mysql的事务隔离与实现