当前位置: 首页 > article >正文

mysql的mvcc

快速搞懂mvcc

  • 全称 multi-version concurrency control 多版本并发控制。
  • 自动开启事务
  • undo log
  • 读视图(read_view)
  • 结果过滤
  • mvcc只在读已提交和可重复读隔离级别下运作
  • 读已提交隔离级别下,
  • 可重复读隔离级别下,
  • 总的来说mvcc是为了提高数据库并发性能而设计的,它实现了读已提交。为了保证并发性能,它本身不加锁。它只在读已提交和可重复读隔离级别下工作。
  • 读已提交隔离级别下,
    • 防止不可重复读:
    • 防止幻读:

全称 multi-version concurrency control 多版本并发控制。

自动开启事务

MySQL默认每个对数据库进行修改的SQL语句都会自动开启事务:insert into ,update,delete from 另外加锁的SQL语句也会自动开启事务:select * from table_name lock in share mode, select * from table_name where condition for update。

undo log

每个事务在修改某条记录的时候都会先将老数据备份入undo log中,然后新增一条记录,并在隐藏字段db_tx_id中记录新增这个条数据的事务id,在隐藏字段db_roll_pointer中记录刚刚备份的原数据的db_row_id(db_row_id也是隐藏字段)。这样每个事务对数据的修改并没有覆盖原有数据。事务提交后,就处于不活跃状态。

读视图(read_view)

每个事务读取数据时会创建一个读视图(read_view),read_view 包含:活跃的事务id列表,最大事务id,最小事务id,创建读视图的事务id。事务id都是自增长的,值越大,说明创建的时间越晚。

结果过滤

然后用read_view过滤查询结果:
查询结果中db_tx_id>最大事务id,说明该结果是由读视图创建后的事务创建的,应不可见,丢弃;
db_tx_id<最小事务id,说明该结果在读视图创建前就已经提交,应可见;
最小事务id<=db_tx_id<=最大事务id,db_tx_id不在活跃的事务id列表中,说明该结果已经提交,应可见,db_tx_id在活跃的事务id列表中,则说明此创建该结果的事务还没提交,该结果应不可见。
这样保证了每个并发事务都读取已提交的结果,而且整个读取过程没有解锁,并发性能得到提升。

mvcc只在读已提交和可重复读隔离级别下运作

mvcc在读已提交和可重复读模式下运行,mvcc最主要的就是实现多个并发事务读已提交的数据,所以读未提交隔离级别下允许读未提交,跟mvcc向北,mvcc是不会运作的。可序列化隔离级别下,事务都是串行的,不存在并发,所以此隔离级别下,mvcc也是不运作的。

读已提交隔离级别下,

事务每次读取都要重新创建视图,在此期间有新事务创建,也有新事务提交,所以每此创建的视图都不一样,用试图过滤出来的结果以及结果的条数也不一样,所以会出现不可重复读(读出的结果变了)和幻读(读出的结果条数变了)。

可重复读隔离级别下,

只有在刚进入事务时会创建一个视图,由于mvcc的过滤原则时只提取已提交的数据,所以随着时间的推移,进入事务之后的查询,能查出来新增的数据的事务id都是比刚进入事务时查出来的数据事务id大,新的数据不会被筛选出来
。所以筛选结果跟第一次一样。此隔离级别下可以保证可重复读,但有些新增或删除的数据可能已提交(第一次没有筛选出来的数据),而活跃的事务id没有更新,导致本该读出来的数据没有读出来,所以避免不了幻读。

总的来说mvcc是为了提高数据库并发性能而设计的,它实现了读已提交。为了保证并发性能,它本身不加锁。它只在读已提交和可重复读隔离级别下工作。

读已提交隔离级别下,

防止不可重复读:

1、将事务隔离级别设为可重复读(推荐)。
2、使用共享(读锁 select…in share mode)(不推荐)。
3、使用排他锁(写锁 select…for update)(不推荐)。

防止幻读:

1、将事务隔离级别设为可重复读,然后使用排他锁select… for update,会自动应用间隙锁(推荐)
2、使用排他锁select… for update,条件用主键筛选,会应用间隙锁(推荐)
3、应用程序自己确保更新的数据条数没有发生变化。


http://www.kler.cn/a/512105.html

相关文章:

  • PHP语言的语法糖
  • Kotlin Bytedeco OpenCV 图像图像54 透视变换 图像矫正
  • MySQL中日期和时间戳的转换:字符到DATE和TIMESTAMP的相互转换
  • MongoDB vs Redis:相似与区别
  • PortSwigger靶场练习---第二关-查找和利用未使用的 API 端点
  • 【PowerQuery专栏】PowerQuery提取XML数据
  • 详解共享WiFi小程序怎么弄!
  • RFID系统安全认证协议及防碰撞算法研究(RFID Security)
  • Linux 存储设备和 Ventoy 启动盘制作指南
  • Linux C\C++方式下的文件I/O编程
  • Oracle 创建并使用外部表
  • JavaWeb项目——如何处理管理员登录和退出——笔记
  • Windows图形界面(GUI)-QT-C/C++ - Qt List Widget详解与应用
  • AUTOSAR从入门到精通-自动驾驶测试技术(二)
  • CSS 合法颜色值
  • 风吹字符起,诗意Linux:一场指令与自由的浪漫邂逅(上)
  • 25春秋杯wp
  • Unity Shader学习日记 part5 CG基础
  • 02_登录窗口
  • leetcode 62. 不同路径
  • CentOS 7中 分区工具fdisk的常用命令【解释来自gpt】
  • PHP For 循环
  • 【RabbitMQ】rabbitmq广播模式的使用
  • Ubuntu 完整卸载 WPS Office (deb包安装版)
  • 【C++篇】红黑树封装 实现map和set
  • 机器人“大脑+小脑”范式:算力魔方赋能智能自主导航