当前位置: 代码网 > it编程>数据库>Mysql > MySQL之InnoDB中的MVCC用法

MySQL之InnoDB中的MVCC用法

2025年06月26日 Mysql 我要评论
1、背景mvcc叫做多版本并发控制,通过维护数据的多个历史版本实现读写分离:读操作访问快照版本,无需加锁,避免阻塞写操作;写操作创建新版本,不影响其它事务的读操作。这种机制支持了读已提交和可重复读两种

1、背景

mvcc叫做多版本并发控制,通过维护数据的多个历史版本实现读写分离:读操作访问快照版本,无需加锁,避免阻塞写操作;写操作创建新版本,不影响其它事务的读操作。

这种机制支持了读已提交可重复读两种事务隔离级别,innodb中是通过隐藏列事务id、版本链、read view实现的mvcc。

2、设置事务的隔离级别

设置事务隔离级别可以通过修改配置文件和通过sql语句,修改的隔离级别有4种:读未提交、读已提交、可重复读、串行化,修改配置文件可以永久生效,查看配置文件中的隔离级别如下:

[root@xxx xxx]# cat /xxx/my.cnf | grep 'transaction_isolation'
transaction_isolation                                      = read-committed

通过sql语句修改是临时生效的,有3种修改方式,一个是会话级设置,只影响当前连接,例如:

mysql> set session transaction isolation level read committed;
query ok, 0 rows affected (0.00 sec)

另一个是全局设置,影响所有连接,例如:

mysql> set global transaction isolation level repeatable read;
query ok, 0 rows affected (0.00 sec)

最后一个是仅对下一个事务生效,例如:

mysql> set transaction isolation level read committed;
query ok, 0 rows affected (0.00 sec)

3、mvcc

【1】版本链

之前讲过隐藏列:row_id、trx_id、roll_pointer,其中row_id不一定存在,当没有主键和唯一索引时,row_id才存在,trx_id是事务id,roll_pointer指向undo日志,通过roll_pointer就可以组成一条版本链,接下来通过如下表和数据来说明:

mysql> show create table student;
+---------+-------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------+
| table   | create table
                                                                                                              |
+---------+-------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------+
| student | create table `student` (
  `id` int not null auto_increment,
  `name` varchar(255) not null default '' comment '姓名',
  primary key (`id`)
) engine=innodb auto_increment=2 default charset=utf8mb4 collate=utf8mb4_0900_ai_ci |
+---------+-------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select * from student;
+----+------+
| id | name |
+----+------+
|  1 | 张三 |
+----+------+
1 row in set (0.00 sec)

接下来分别在两个事务中更新数据,假设事务id分别为20和50:

时间顺序事务a,事务id=20事务b,事务id=50
t1开始事务开始事务
t2update student set name = ‘李四’ where id = 1;
t3提交事务
t4update student set name = ‘王五’ where id = 1;
t5提交事务

此时版本链如下:

在这里插入图片描述

name为王五的代表最新记录,name为李四和张三的为undo日志。

【2】readview

  • 对于未提交读的隔离级别事务来说,由于可以读到未提交事务修改的记录,直接读取最新的版本就好了;
  • 对于串行化隔离级别的事务来说是使用加锁的方式来访问记录的;
  • 对于读已提交和可重复读隔离级别的事务来说,只能读到已提交事务的结果。所以核心问题就是版本链中哪一个版本对当前事务是可见的,所有就有了readview,readview中包含4个部分:
名称含义
m_ids生成readview时当前系统中活跃的读写事务id列表
min_trx_idm_ids中的最小值
max_trx_id分配给下一个事务的id值,不是m_ids中的最大值
creator_trx_id生成readview的事务id,只读事务中为0

通过readview的属性,我们就能判断对记录版本链中的哪一个版本可见,判断规则如下:

1、如果被访问版本的trx_id与readview的中的creator_trx_id相同,说明当前事务再访问自己修改的记录,所以该版本可以被当前事务访问。

2、如果被访问版本的trx_id小于readview的中的min_trx_id值,说明生成该版本的事务在当前事务之前已经提交,所以该版本可以被当前事务访问。

3、如果被访问版本的trx_id大于readview的中的max_trx_id值,表明生成该版本的事务在当前事务之后开启,所以该版本不可以被当前事务访问。

4、如果被访问的版本的trx_id在readview的min_trx_id和max_trx_id之间,需要判断trx_id是否在m_ids中,在就说明该版本的事务还是活跃的,不可以被访问;不在就说明该版本已经提交,可以被访问。

如果某个版本的数据对当前事务不可见,就顺着版本链去判断下一个版本的数据,一直到最后一个版本,如果最后一个版本也不可见,那查询结果就不包含这条记录。

【3】readview的生成时机

隔离级别生成readview时机
读已经提交每次读取数据前都生成一个readview
可重复读第一次读取数据时生成一个readview

4、总结

mvcc是一种数据库并发控制技术,通过维护数据的多个历史版本实现读写操作的并行化,从而提升性能并解决事务隔离性问题。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

  • mysql中的数据目录用法及说明

    mysql中的数据目录用法及说明

    1、背景安装mysql之后,在安装目录下会有一个data目录,我们创建的数据库、创建的表、插入的数据都是存储在这个目录中,可以大概了解一下这个目录下是怎么存储数... [阅读全文]
  • MySQL之InnoDB存储页的独立表空间解读

    1、背景我们往一张表里插入的行数据是存储在页上的,一张页的大小为16kb,数据量大的时候一张页不可能存储完一张表里的所有数据,所以需要多张页来进行存储,这多张页所在的存储空间就叫表…

    2025年06月26日 数据库
  • MySQL中的InnoDB单表访问过程

    MySQL中的InnoDB单表访问过程

    1、背景mysql通过查询条件查询到结果的过程就叫访问方法,一条查询语句的访问方法有很多种,接下来我们就来讲一下各种访问方法。2、环境创建表:mysql>... [阅读全文]
  • MySQL 中 ROW_NUMBER() 函数最佳实践

    MySQL 中 ROW_NUMBER() 函数最佳实践

    mysql 中row_number()函数详解row_number()是 sql 窗口函数中的一种,用于为查询结果集中的每一行分配一个​​唯一的连续序号​​。与... [阅读全文]
  • MySQL中的表连接原理分析

    MySQL中的表连接原理分析

    1、背景在进行sql查询时有时需要多张表的查询结果组成一个共同的结果返回,这时就用到了mysql中连接的用法,接下来就以两张表来讲解表连接的原理。2、环境创建两... [阅读全文]
  • MySQL InnoDB中的Buffer Pool用法及说明

    MySQL InnoDB中的Buffer Pool用法及说明

    1、背景mysql数据是存储在磁盘上的,但是从磁盘上读取数据的速度太慢,所以就需要把数据从磁盘读取在内存中,申请的这块内存就叫buffer pool,也就是缓存... [阅读全文]

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com