首页 > 数据库 >MYSQL多版本并发控制(MVCC)

MYSQL多版本并发控制(MVCC)

时间:2025-01-15 13:04:22浏览次数:3  
标签:事务 读取 密码 Read MVCC 并发 MYSQL ID View

MYSQL支持并发事务,事务的有四个特性(ACID):

  • 原子性(Atomicity):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节,而且事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样;
  • 一致性(Consistency):数据库只会从一个一致的状态转换到另一个一致的状态。事务的执行不会违反数据库的任何完整性约束和规则。如果事务违反了这些规则,比如尝试插入重复的键值或违反外键约束,数据库管理系统将拒绝该事务,确保数据的完整性不被破坏。
  • 隔离性(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
  • 持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

持久性是通过 redo log(重做日志) 来保证。原子性是通过 undo log(回滚日志) 来保证。

隔离性是通过 MVCC来保证的。一致性是由持久性、原子性和隔离性共同保证的。


事务隔离性

本文我们介绍的就是MVCC机制。事务的隔离性有四个级别:

  • 读未提及:事务可以读取到其他未提交事务的最新修改。
  • 读提交:事务只能读取到其他事务已经提交的数据。
  • 可重复读:在一个事务中多次读取同一数据集合将得到相同的结果。
  • 串行化:事务会完全串行执行在这种模式下,事务完全隔离。

在并发事务中会存在以下问题:

  • 脏读:一个事务读取了另一个未提交事务的数据。 
  • 不可重复读: 在一个事务中,多次读取同一数据集合,由于其他事务的修改,得到的结果不一致。
  • 幻读:在一个事务中,多次查询同一范围的数据,由于其他事务的插入,返回的行数不一致。

对于不同隔离级别会发生的问题如下:

 对于这四种隔离级别的实现,在“读未提交”隔离级别下,事务直接读取最新数据。在“串行化”隔离级别下,事务通过加读写锁来避免并发访问,确保事务的串行执行。串行化事务会使用排他锁来访问数据,其他事务不能并发访问相同的数据。

对于读提交和可重复读都是通过MVCC机制实现的。


版本链

InnoDB中的每条数据都有两个隐藏字段:

  • Transaction ID (InnoDB): 记录创建或最后一次修改行的事务ID。每个事务都有一个唯一的事务ID
  • Rollback Pointer (InnoDB): 回滚指针用于指向该行数据的上一个版本,这是为了支持事务的回滚操作。如果事务需要回滚,InnoDB 可以使用回滚指针来恢复到之前的状态。

假设有一个用户表,表中有三个字段:用户ID,用户名,用户密码。我们插入一条数据:ID为 1,用户名为 knight ,密码为 123456 。实际记录的数据如下:

在 undo log 在存储着该条数据的一整条版本链,每次事务对数据行进行修改时,都会生成一条undo log记录,这些记录通过roll_pointer指针相互连接,形成一个版本链表,从而记录了数据的历史版本


Read View

Read View 中有四个字段:

  • m_ids:当前活跃的事务ID集合。这个字段记录了在Read View创建时,所有尚未提交的事务的ID。
  • min_trx_id:最小活跃事务ID。这个字段记录了Read View创建时,所有活跃事务中最小的事务ID。
  • max_trx_id:预分配事务ID,当前最大事务ID+1。这个字段表示在Read View创建时,下一个将要被分配的事务ID。
  • creator_trx_id:Read View创建者的事务ID。

基于undo log 的版本链与Read view 我们就能控制了事务的可见性。


可重复读

对于可重复读,MYSQL会在事务开始时创建一个Read view。在整个事务期间使用的都是这个Read view。对于可重复读,只能看到 预分配事务ID 以下(不包含)且不在活跃事务ID集合内的事务修改的记录。这些事务在当前事务启动时都已经提交。

执行开始事务命令,并不意味着启动了事务。在 MySQL 有两种开启事务的命令:

  • begin/start transaction 
  • start transaction with consistent snapshot

这两种开启事务的命令,事务的启动时机是不同的执行 begin/start transaction 命令后,并不代表事务启动了。只有在执行这个命令后,执行了增删查改操作的 SQL 语句,事务才会启动。执行了 start transaction with consistent snapshot  命令,就会马上启动事务。

假设有事务A (ID为61),事务B(ID为62),隔离级别为可重复读。A启动后,紧接着B启动,A B 的 Read View 如下:

有数据如下:

A B 按顺序执行如下操作:

  1. B  读取 knight 密码 密码为 123456。
  2. A  修改 knight 密码为 000000。
  3. B  读取 knight 密码,密码为 123456。
  4. A  提交事务。
  5. B  读取 knight 密码,密码为 123456。

B第一次读取 knight 密码,B 的 Read View  中 min_trx_id 最小活跃事务ID为 61,B 读取到记录数据的 Transaction ID(最后修改事务ID)为 50 ,最后修改记录的事务在当前事务创建前提交,可以看到这条记录,读取结果为 123456 。

A 修改密码,版本链更新。

B 第二次读取 knight 密码,记录的 Transaction ID(最后修改事务ID)为 61 ,61 在 B 的 m_ids 中,所以该记录的修改在 B 创建时未提交,该记录对 B 不可见,B 通过回滚指针找到上一条记录,判断其可见性——可见,查询结果为密码为 123456 。

A 提交事务,版本链不变,B 第三次读取 knight 密码,查询结果仍为密码为 123456 。


读提交

读提交隔离级别是在每次读取数据时,都会生成一个新的 Read View。对于读提交,可见性仍是预分配事务ID 以下(不包含)且不在活跃事务ID集合内的事务修改的记录。

假设有事务A (ID为61),事务B(ID为62),隔离级别为读提交。A启动后,紧接着B启动,A B 的 Read View 如下:

有数据如下: 

A B 按顺序执行如下操作:

  1. B  读取 knight 密码 密码为 123456。
  2. A  修改 knight 密码为 000000。
  3. B  读取 knight 密码,密码为 123456。
  4. A  提交事务。
  5. B  读取 knight 密码,密码为 000000。

 B第一次读取,Read View如下:

B第一次读取 knight 密码,B 的 Read View  中 min_trx_id 最小活跃事务ID为 61,B 读取到记录数据的 Transaction ID(最后修改事务ID)为 50 ,最后修改记录的事务在当前Read View创建前提交,可以看到这条记录,读取结果为 123456 。

A 修改密码,版本链更新。

B 第二次读取 knight 密码,Read View如下:

B 第二次读取 knight 密码,记录的 Transaction ID(最后修改事务ID)为 61 ,61 在 B 的 m_ids 中,所以该记录的修改在Read View创建时未提交,该记录对 B 不可见,B 通过回滚指针找到上一条记录,判断其可见性——可见,查询结果为密码为 123456 。

A 提交事务,B第三次读取,Read View 如下:

 B 第三次读取 knight 密码,记录的 Transaction ID(最后修改事务ID)为 62 ,所以该记录的修改在Read View创建时提交,该记录对 B 可见,查询结果为密码为000000 。

标签:事务,读取,密码,Read,MVCC,并发,MYSQL,ID,View
From: https://blog.csdn.net/2301_80926085/article/details/144728011

相关文章

  • 5、提升Java的并发性
    CompletableFuture及反应式编程背后的概念:::info❏线程、Future以及推动Java支持更丰富的并发API的进化动力❏异步API❏从“线框与管道”的角度看并发计算❏使用CompletableFuture结合器动态地连接线框❏构成Java9反应式编程FlowAPI基础的“发布-订阅”协议❏反应式......
  • 基于PHP+Mysql 论坛信息系统(源码+LW+部署讲解+数据库+ppt)
    !!!!!!!!!选题不知道怎么选不清楚自己适合做哪块内容都可以免费来问我避免后期給自己答辩找麻烦增加难度(部分学校只有一次答辩机会没弄好就延迟毕业了)会持续一直更新下去有问必答一键收藏关注不迷路源码获取:https://pan.baidu.com/s/1aRpOv3f2sdtVYOogQjb8jg?pwd=jf1d提取码:......
  • 基于PHP+Mysql人员信息管理(源码+LW+部署讲解+数据库+ppt)
    !!!!!!!!!选题不知道怎么选不清楚自己适合做哪块内容都可以免费来问我避免后期給自己答辩找麻烦增加难度(部分学校只有一次答辩机会没弄好就延迟毕业了)会持续一直更新下去有问必答一键收藏关注不迷路源码获取:https://pan.baidu.com/s/1aRpOv3f2sdtVYOogQjb8jg?pwd=jf1d提取码:......
  • 基于PHP+Mysql购物管理系统(源码+LW+部署讲解+数据库+ppt)
    !!!!!!!!!选题不知道怎么选不清楚自己适合做哪块内容都可以免费来问我避免后期給自己答辩找麻烦增加难度(部分学校只有一次答辩机会没弄好就延迟毕业了)会持续一直更新下去有问必答一键收藏关注不迷路源码获取:https://pan.baidu.com/s/1aRpOv3f2sdtVYOogQjb8jg?pwd=jf1d提取码:......
  • MySQL(高级特性篇) 07 章——InnoDB数据存储结构
    一、数据库的存储结构:页索引结构给我们提供了高效的索引方式,不过索引信息以及数据记录都是保存在文件上的,确切地说是存储在页结构中。另一方面,索引是在存储引擎中实现的,MySQL服务器上的存储引擎负责对表中数据的读取和写入工作。不同存储引擎中存放的格式一般是不同的,甚至有的......
  • MySQL 8.0 如何禁用 ONLY_FULL_GROUP_BY
    在MySQL8中,ONLY_FULL_GROUP_BY​是默认启用的SQL模式之一。如果你希望禁用ONLY_FULL_GROUP_BY​,可以通过以下几种方式实现:方法1:临时禁用(仅对当前会话有效)你可以通过修改当前会话的sql_mode​来临时禁用ONLY_FULL_GROUP_BY​。步骤:查看当前的sql_mode​......
  • 东软云医院HIS系统【Swing窗口+MySQL】(Java课设)
        客官进来看一眼呗,有惊喜!【帮你解决烦恼】:Java课设和计Java毕设太难不会做怎么办?系统类型Swing窗口类型+Mysql数据库存储数据使用范围适合作为Java课设!!!部署环境jdk1.8+Mysql8.0+Idea或eclipse+jdbc运行效果本系统源码地址:东软云医院HIS系统【Swing窗口+MySQL】......
  • 如何在 MySQL 中批量删除指定 ID 范围内的数据?
    在MySQL中批量删除指定ID范围内的数据可以通过 DELETE 语句结合 WHERE 子句来实现。以下是详细的步骤和示例:1.使用 DELETE 语句删除指定ID范围内的数据假设你有一个名为 mydb 的表,并且你想删除 id 大于等于10的所有记录。可以使用以下SQL语句:sql DE......
  • 服务器MySQL权限管理
    1.查看权限SHOWGRANTSFOR'用户'@'ip地址';2.设置及授权密码1.授权格式GRANT权限[权限,权限...]ON数据库.数据表TO'用户名'@'IP地址'; GRANT权限[权限,权限...]ON数据库.数据表TO'用户名'@'IP地址'IDENTIFIEDBY'密码'; 2.权限类型权......
  • MySQL行专列
    一、行转列1、使用case…when…then2、使用SUM(IF())生成列3、使用SUM(IF())生成列+WITHROLLUP生成汇总行4、使用SUM(IF())生成列,直接生成汇总结果,不再利用子查询5、使用SUM(IF())生成列+UNION生成汇总行,并利用IFNULL将汇总行标题显示为Total6、动态查询列值......