MVCC
2023-04-18 20:20:33 0 举报
MySQL MVCC版本控制说明
作者其他创作
大纲/内容
name=Jack
可以看到,每次修改行记录都会更新 trx_id 和 roll_pointer 这两个隐藏字段,之前的多个数据快照对应的 undo log 会通过 roll_pointer 指针串联起来,从而形成一个版本链。那么问题又来了,一个记录会被一堆事务进行修改,一个记录上会存在许许多多的 undo log,那么对于其中某一个事务来说,它能看见哪些 undo log?或者说,对于其中某一个事务来说,它能够根据哪些 undo log 执行回滚操作?
name=Iris
age=20
事务C
age=18
事务A
id=1
trx_id=300
.....
参考资料:https://www.zhihu.com/question/263820564/answer/2271129726
Undo Log 版本链
NULL
roll_pointer
ReadView 机制
事务B
那自己修改的值,自己能不能读到呢?肯定是可以读到。上面的例子我们只涉及到了 ReadView 中的前三个字段,而 creator_trx_id 就与自己读自己的修改有关,所以这里还是图解出来让大家更进一步理解下 ReadView 机制:假设事务 C 的修改已经提交了,然后事务 B 更新了这行记录,把 age = 20 改成了 age = 66,然后,事务 B 再来查询这条记录,发现 trx_id = 200 与 ReadView 里的 creator_trx_id = 200 一样,这就说明这是我自己刚刚修改的,当然可以被查询到。row.trx_id = ReadView.creator_trx_id √
InnoDB 存储引擎中每条行记录其实都拥有两个隐藏的字段:trx_id 和 roll_pointer:trx_id:就是最近更新这条行记录的事务 IDroll_pointer:就是指向之前生成的 undo log 的指针
事务通过用当前事务(或语句,取决于隔离级别)的ReadView来判断一个事务id的操作是否对当前事务可见。判断可见性的伪代码如下:
trx_id=500
age=66
在 MySQL 中,每条记录在更新的时候都会同时记录一条回滚操作(也就是 undo log),当前记录上的最新值,通过回滚操作,都可以得到前一个状态的值。简单理解,undo log 就是每次操作的反向操作,比如比如当前事务执行了一个插入 id = 100 的记录的操作,那么 undo log 中存储的就是删除 id = 100 的记录的操作。也就是说,B+ 索引树上对应的记录只会有一个最新版本,但是 InnoDB 可以根据 undo log 得到数据的历史版本。同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。
trx_id = 300 存在于 ReadView的m_ids中,无法查询
那如果在事务 B 的执行期间,突然开了一个 id = 500 的事务 D,然后更新了这行记录的 age = 88 并且还提交了,然后事务 B 再去读这行记录,能读到吗?答案是不能的。因为这个时候事务 B 再去查询这行记录,就会发现 trx_id = 500 大于 ReadView 中的 max_trx_id = 301,这说明事务 B 执行期间,有另外一个事务更新了数据,所以不能查询到另外一个事务的更新。row.trx_id >= ReadView.max_trx_id ×那通过上述的例子,我们得出的结论是,通过 undo log 版本链和 ReadView 机制,可以保证一个事务只可以读到该事务自己修改的数据或该事务开始之前的数据。
trx_id=200
trx_id=100
事务D
ReadView 机制就是用来判断当前事务能够看见哪些版本的,一个 ReadView 主要包含如下几个部分:m_ids:生成 ReadView 时有哪些事务在执行但是还没提交的(称为 “活跃事务”),这些活跃事务的 id 就存在这个字段里min_trx_id:m_ids 里最小的值max_trx_id:生成 ReadView 时 InnoDB 将分配给下一个事务的 ID 的值(事务 ID 是递增分配的,越后面申请的事务 ID 越大)creator_trx_id:当前创建 ReadView 事务的 ID
Select
IsVisible(trx_id) if (trx_id == creator_trx_id) // 当前事务 return true; else if (trx_id <= min_trx_id) // ReadView创建时,事务已提交或者就是当前最小事务 return true; else if (trx_id >= max_trx_id) // ReadView创建时,事务还未被创建 return false; else if (min_trx_id < trx_id < max_trx_id) // ReadView创建时,事务正在执行,但未提交 return false else // ReadView创建时,事务已提交 return true;
age=88
0 条评论
回复 删除
下一页