MySQL的MVCC

673 字
3 分钟
MySQL的MVCC

MVCC#

readview#

image 32
image 32

RC、RR隔离级别在事务开始时会生成一个 readview, 包含以下要素信息 creator_trx_id 生成该 readview 的事务的事务id trx_ids 在生成 readview 时当前系统中活跃的读写事务的事务id列表(开启事务但未提交) up_limit_id 生成 readview 时 活跃trx_ids 中的最小值 low_limit_id 生成 readview 时 系统中应该分配给下一个事务的id值

有了这个readview,这样在访问某条记录时,只需要按照下面的步骤判断记录的某个版本是否可见

  1. ==record_trx_id = creator_trx_id== 表明当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问
  2. ==record_trx_id < up_limit_id== 表明生成该版本的事务在当前事务生成 readview 前已经提交,所以该版本可以被当前事务访问
  3. ==record_trx_id >= low_limit_id== 表明生成该版本的事务在当前事务生成 readview 后才开启,所以该版本不可以被当前事务访问
  4. ==record_trx_id between min_trx_id and max_trx_id && record_trx_id not in trx_ids== 说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问
  5. ==record_trx_id between min_trx_id and max_trx_id && record_trx_id in trx_ids== 说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问

mysql 源码中 readview 结构的说明

struct read_view_struct{
ulint type; /*!< VIEW_NORMAL, VIEW_HIGH_GRANULARITY */
undo_no_t undo_no;/*!< 0 or if type is
VIEW_HIGH_GRANULARITY
transaction undo_no when this high-granularity
consistent read view was created */
trx_id_t low_limit_no;
/*!< The view does not need to see the undo
logs for transactions whose transaction number
is strictly smaller (<) than this value: they
can be removed in purge if not needed by other
views */
trx_id_t low_limit_id;
/*!< The read should not see any transaction
with trx id >= this value. In other words,
this is the "high water mark". */
trx_id_t up_limit_id;
/*!< The read should see all trx ids which
are strictly smaller (<) than this value.
In other words,
this is the "low water mark". */
ulint n_trx_ids;
/*!< Number of cells in the trx_ids array */
trx_id_t* trx_ids;/*!< Additional trx ids which the read should
not see: typically, these are the active
transactions at the time when the read is
serialized, except the reading transaction
itself; the trx ids in this array are in a
descending order. These trx_ids should be
between the "low" and "high" water marks,
that is, up_limit_id and low_limit_id. */
trx_id_t creator_trx_id;
/*!< trx id of creating transaction, or
0 used in purge */
UT_LIST_NODE_T(read_view_t) view_list;
/*!< List of read views in trx_sys */
};

MySQL的RR事务隔离并没有完全防止幻读#

可以使用以下例子重现,该例子来自stackoverflow

create table ab(a int primary key, b int);
Tx1:
begin;
select * from ab; // empty set
Tx2:
begin;
insert into ab values(1,1);
commit;
Tx1:
select * from ab; // empty set, expected phantom read missing.
update ab set b = 2 where a = 1; // 1 row affected.
select * from ab; // 1 row. phantom read here!!!!
commit;

📎 参考文章#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

MySQL的MVCC
https://blog.sephy.top/posts/mysql的mvcc/
作者
虾米
发布于
2024-02-14
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
虾米
coder
分类
标签
站点统计
文章
61
分类
4
标签
52
总字数
64,663
运行时长
0
最后活动
0 天前
站点信息
构建平台
GitHub Actions
博客版本
Firefly v6.13.9
文章许可
CC BY-NC-SA 4.0