跳过正文
  1. 全部/
  2. 笔记/
  3. 面试/
  4. 数据库/
  5. MySQL/

7 事务隔离级别 MVCC

目录

并发存在的问题
#

  1. 脏读:一个事务「读到」了另一个「未提交事务修改过的数据」
  2. 不可重复度:在一个事务内多次读取同一个数据,如果出现前后两次读到的数据不一样的情况,就意味着发生了「不可重复读」现象。
  3. 幻读:在一个事务按照条件查询数据时,没有对应的数据行,但在插入数据后,这行数据又存在。

事务的隔离级别
#

读未提交:脏读,不可重复读,幻读 读提交:不可重复读,幻读 可重复读:幻读 串行化

  • 当前读:读取的是最新版本
  • 快照读:读取的是记录数据的可见版本

mvcc实现
#

隐藏字段
#

Pasted image 20260319214937.png

trx_id,当一个事务对某条聚簇索引记录进行改动时,就会把该事务的事务 id 记录在 trx_id 隐藏列里; roll_pointer,每次对某条聚簇索引记录进行改动时,都会把旧版本的记录写入到 undo 日志中,然后这个隐藏列是个指针,指向每一个旧版本记录,于是就可以通过它找到修改前的记录。

undolog
#

undo log版本链

readView
#

Pasted image 20260319215303.png

Pasted image 20260517214317.png

  • 如果记录的 trx_id 值小于 Read View 中的 min_trx_id 值,表示这个版本的记录是由"创建 Read View 之前就已经提交的事务"生成的,所以该版本对当前事务可见

  • 如果记录的 trx_id 值大于等于 Read View 中的 max_trx_id 值,表示这个版本的记录是由"创建 Read View 之后才启动的事务"生成的,所以该版本对当前事务不可见

  • 如果记录的 trx_id 值介于 min_trx_id 和 max_trx_id 之间(即 min_trx_id <= trx_id < max_trx_id),说明该事务的 id 在 Read View 创建之前就已经分配出去了,此时需要进一步判断 trx_id 是否在 m_ids 列表中:

    • 如果 trx_id  m_ids 列表中,表示生成该版本记录的事务在创建 Read View 的那一刻仍然活跃(尚未提交),所以该版本对当前事务不可见
    • 如果 trx_id 不在 m_ids 列表中,表示该事务虽然 id 已分配,但在创建 Read View 时已经提交,所以该版本对当前事务可见

读提交」隔离级别是在每个 select 都会生成一个新的 Read View,也意味着,事务期间的多次读取同一条数据,前后两次读的数据可能会出现不一致,因为可能这期间另外一个事务修改了该记录,并提交了事务。

可重复读」隔离级别是启动事务时生成一个 Read View,然后整个事务期间都在用这个 Read View,这样就保证了在事务期间读到的数据都是事务启动前的记录。

Reply by Email