mysql事务隔离性的实现

mysql事务隔离性的实现

MVCC机制(多版本并发控制)

  • Mysql在读已提交和可重复读隔离级别下都实现了MVCC机制。
  • 主要是保存数据在某个时间点的快照实现的。
  • mysql在每行记录后面,保存了两个隐藏列,分别为:创建事务id和删除事务id
  • MVCC机制的实现就是通过read-view机制与undo版本链比对机制,使得不同的事务会根据数据版本链对比规则读取同一条数据在版本链上的不同版本数据。
  • 当执行select操作的时候,mysql底层会带上过滤条件:

    • 创建事务id <= max(当前事务id, 已提交的最大事务id),保证该事务读到的数据,要么是开始前就已经存在的,要么是自身插入或修改后的。

    • 删除事务id > max (当前事务id, 已提交的最大事务id) 或 删除事务id未定义。保证事务读到的行,在事务开始前没有被删除

undo日志版本链

undo日志版本链是指一行数据被多个事务依次修改过后,在每个事务修改完后,Mysql会保留修改前的数据undo回滚日志,并且用两个隐藏字段trx_id和roll_pointer把这些undo日志串联起来形成一个历史记录版本链。

  • roll_pointer: 可以根据roll_pointer找到之前的老数据,如果事务失败,就可以找到之前的老数据
  • 每次修改,就是写进新的事务id,以及把回滚指针指向上一条数据的位置

read view机制详解

  • 可重复读隔离级别,当事务开启,执行任何查询sql时会生成当前事务的一致性视图read-view,该视图在事务结束 之前都不会变化(如果是读已提交隔离级别在每次执行查询sql时都会重新生成)。

  • 这个视图由执行查询时所有未提交事务id数组(数组里最小的id为min_id)和已创建的最大事务id(max_id)组成,事务里的任何sql查询结果需要从对应版本链里的最新数据开始逐条跟read-view做比对从而得到最终的快照结果。

Eg:

假设当前新开启了一个事务A,事务id为300,在该事务之前有两个事务B和C,均id分别为100和200。

当事务A执行第一个select的时候,事务B已经提交了,而事务C还没有提交,那么此时的read-view为【200】,300

版本链比对规则:

  1. 如果 row 的 trx_id 落在绿色部分( trx_id<min_id ),表示这个版本是已提交的事务生成的,这个数据是可见的;

  2. 如果 row 的 trx_id 落在红色部分( trx_id>max_id ),表示这个版本是由将来启动的事务生成的,是不可见的(若

row 的 trx_id 就是当前自己的事务是可见的);

  1. 如果 row 的 trx_id 落在黄色部分(min_id <=trx_id<= max_id),那就包括两种情况

​ a. 若 row 的 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见(若 row 的 trx_id 就是当前自己的事务是可见的);

​ b. 若 row 的 trx_id 不在视图数组中,表示这个版本是已经提交了的事务生成的,可见。

删除的情况

对于删除的情况可以认为是update的特殊情况,会将版本链上最新的数据复制一份,然后将trx_id修改成删除操作的 trx_id,同时在该条记录的头信息(record header)里的(deleted_flag)标记位写上true,来表示当前记录已经被删除,在查询时按照上面的规则查到对应的记录如果delete_flag标记位为true,意味着记录已被删除,则不返回数据。

注意:

begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个修改操作InnoDB表的语句,

事务才真正启动,才会向mysql申请事务id,mysql内部是严格按照事务的启动顺序来分配事务id的。

加锁

串行化隔离级别为了保证较高的隔离性是通过将所有操 作加锁互斥来实现的。


mysql事务隔离性的实现
http://example.com/mvcc介绍/
作者
Panyurou
发布于
2022年6月13日
许可协议