设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间23 现在时间23 缓存数据 荣耀也罢,屈辱也罢,都要以平和的心态去面对,少一些无奈与感慨,多一份从容和淡然。晚安!

荣耀也罢,屈辱也罢,都要以平和的心态去面对,少一些无奈与感慨,多一份从容和淡然。晚安!

查看: 1086|回复: 3

MySQL多版本并发控制mvcc原理浅析

[复制链接]

  离线 

TA的专栏

  • 打卡等级:常驻代表
  • 打卡总天数:32
  • 打卡月天数:0
  • 打卡总奖励:436
  • 最近打卡:2025-11-20 19:47:10
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
307
主题
271
精华
0
金钱
1345
积分
646
注册时间
2023-2-11
最后登录
2025-11-20

发表于 2024-7-22 07:35:13 | 显示全部楼层 |阅读模式
目录


  • 1.mvcc简介

    • 1.1mvcc定义
    • 1.2mvcc解决的问题
    • 1.3当前读与快照读

  • 2.mvcc原理

    • 2.1隐藏字段
    • 2.2版本链
    • 2.3ReadView
    • 2.4读视图生成原则

  • 3.rc和rr隔离级别下mvcc的不同

1.mvcc简介


1.1mvcc定义

mvcc(Multi Version Concurrency Control),多版本并发控制,是一种数据库的并发控制机制。它用于管理事务并发执行时对数据的访问和修改,保证在多个事务同时对数据库进行读写操作,不会出现数据不一致或丢失的情况

1.2mvcc解决的问题

当多个事务同时访问数据库中的相同数据时,可能会有几种情况:

  • 读:多个事务都是读操作,不会产生并发问题
  • 读+写:事务有读有写,那么会产生脏读、不可重复读、幻读的问题
  • 写:多个事务同时写,可能会产生数据丢失、覆盖等问题
针对以上问题,在读+写的情况下,通常需要加锁来解决问题,mysql的innodb实现了mvcc来更好的处理读写冲突,做到不用加锁,实现非阻塞并发读
在都是写操作的情况下,只能通过加锁的方式解决。

1.3当前读与快照读

当前读:读取的是最新版本的数据,保证读取时不会有其他事务修改数据,需要对记录加锁
加共享锁,读不受影响,写会被阻塞
  1. select ... lock in share mode;
复制代码
加排他锁,读和写都被阻塞(快照读不受影响)
  1. select ... for update;
复制代码
更新、插入、删除操作以及串行化隔离级别都是当前读
快照读:每一次修改数据,都会在undolog中存有原始记录(快照),快照读就是读取某一版本的记录。这种方式能够不加锁读数据,但是可能会读到旧的数据。一般的查询都是快照读
  1. select * from tablename;
复制代码
2.mvcc原理

mvcc主要通过行记录中的隐藏字段、undolog和readview实现的

2.1隐藏字段

mysql的innodb引擎中,在每一行记录中除了自定义的字段,还有3个隐藏的字段(innodb引擎)

  • row_id:如果表没有自定义主键,那么会自动生成row_id作为主键
  • trx_id:记录修改、新增这条记录的事务id
  • roll_pointer:回滚指针,指向当前记录的上一个版本

2.2版本链

在修改数据时,mysql会向undolog中记录数据原来的快照,用于进行回滚操作。undolog还能用来实现mvcc
如以下例子,mvcc生成版本链:
当事务1001(trx_id=1001)执行了
  1. insert into user values(1,'竹子',23) 
复制代码
之后:
1.png

当事务1002(trx_id=1002)执行了
  1. update user set name='竹笋' where id=1 
复制代码
之后:
2.png

当事务1003(trx_id=1003)执行了
  1. update user set name='竹叶' where id=1 
复制代码
之后:
3.png

可以看到,不同版本的数据被指针连接起来形成了一个链表。
当我们要读取时,如何判断该读取哪个版本呢?这就与生成的
  1. 读视图
复制代码
有关了。

2.3ReadView

读视图用于决定事务可以读到哪个版本的数据
它包含以下主要信息:

  • trx_ids:当前mysql中所有活跃的事务id集合(没提交或回滚的事务集)
  • low_limit_id:当前出现的最大的事务id+1,表示下一个要分配的事务id
  • up_limit_id:当前活跃的事务id集合中,最小的事务id
  • creator_trx_id:生成该ReadView视图的事务的id
MySQL5.7版本的源码对于这些信息的定义如下:
4.png

插入一个注意事项:🐭🐮🐯🐰🐉🐍🐴🐑🐒🐔🐶🐷
  1. start transaction
复制代码
不代表立即生成ReadView,而是在事务中第一次快照读的时候生成ReadView
,具体参考MySQL可重复读隔离级别下开启事务的一个注意事项
想要开启事务时就生成ReadView,请使用
  1. start transaction with consistent snapshot;
复制代码
2.4读视图生成原则

ReadView定义了一个可见性算法,当事务进行快照读时,依据该算法判断事务能够读取哪个快照。
源码的可见性判断逻辑如下:(下载源码可访问:官网,操作系统选择
  1. Source Code
复制代码
)
  1. /** Check whether the changes by id are visible.
  2.         @param[in]        id        transaction id to check against the view
  3.         @param[in]        name        table name
  4.         @return whether the view sees the modifications of id. */
  5. //判断某个版本的数据是否对当前事务可见
  6. bool changes_visible(
  7.     trx_id_t                id,
  8.     const table_name_t&        name) const
  9.     MY_ATTRIBUTE((warn_unused_result)) {
  10.     ut_ad(id > 0);
  11.     //快照的id小于活跃事务id集合中的最小事务id 或者 快照的id等于创建这个视图的事务id
  12.     if (id < m_up_limit_id || id == m_creator_trx_id) {
  13.         return(true);
  14.     }
  15.     //检查快照id是否合法,如果快照的id大于等于下一要分配的事务id,则需要抛出警告信息(会出现这种情况吗?)
  16.     check_trx_id_sanity(id, name);
  17.     //快照的id大于等于下一要分配的事务id
  18.     if (id >= m_low_limit_id) {
  19.         return(false);
  20.     }
  21.     //当前不存在活跃的事务
  22.     else if (m_ids.empty()) {
  23.         return(true);
  24.     }
  25.     const ids_t::value_type*        p = m_ids.data();
  26.     //通过二分查找判断快照id是否在活跃事务集合中,存在则快照不可见,不存在则快照可见
  27.     return(!std::binary_search(p, p + m_ids.size(), id));
  28. }
复制代码

  • 快照id等于当前事务id时(trx_id=creator_trx_id),说明该版本是当前事务修改的,该快照对当前事务可见
  • 快照id小于活跃事务的最小id(trx_id<up_limit_id),说明该版本对应的事务已经提交了,该快照对当前事务可见
  • 快照id大于等于下一个要分配的事务id(trx_id>=low_limit_id),则该快照对当前事务不可见
  • 快照id小于下一个要分配的事务id并且活跃事务id数量为0(trx_id<low_limit_id && trx_ids.size==0),则该快照对当前事务可见
  • 当以上条件都不满足,则在活跃事务id集合里查找快照id,如果不存在,则可见,否则不可见

3.rc和rr隔离级别下mvcc的不同

mvcc主要用来解决rc(读已提交)隔离级别下的脏读和rr(可重复读)隔离级别的不可重复读问题,所以mvcc只在rc和rr隔离级别下生效。
区别在于,rc级别下,每一次快照读都会生成一个最新的ReadView;RR级别下,只有事务中的第一次快照读会生成ReadView,之后的快照读会使用第一次生成的ReadView
事务能否查询到其他事物修改的数据,取决于ReadView,而rc和rr两个级别的ReadView生成方式不同,就导致了事务可见性不同。(rc级别下一个事务可以查询到其他事物在此期间修改并提交的数据,因为它的每次查询都会生成新的ReadView;rr级别下事务无法查询到其他事物在此期间修改并提交的数据,因为他的ReadView只在第一次快照读生成)
到此这篇关于MySQL多版本并发控制mvcc原理浅析的文章就介绍到这了,更多相关MySQL多版本并发控制mvcc内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
18
积分
16
注册时间
2022-12-24
最后登录
2022-12-24

发表于 2024-10-10 17:38:49 | 显示全部楼层
路过,支持一下
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
20
积分
20
注册时间
2022-12-25
最后登录
2022-12-25

发表于 2025-3-19 02:31:25 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
11
积分
2
注册时间
2024-11-13
最后登录
2024-11-13

发表于 前天 00:19 | 显示全部楼层
感谢楼主,顶。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼
4楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表