MYSQL进阶-InnoDB引擎之MVCC
MVCC多版本并发控制基本概念
当前读
读取的是记录的最新版本,读取时要保证其他并发事务不能修改当前记录,会对当前记录加锁。比如日常操作中的:
- select... lock in share mode (共享锁/读锁)
- select... for update (写锁)
- insert
- delete
- update
快照读
MVCC的作用:在快照读的时候通过MVCC查找对应的历史版本
简单的select... 不加锁就是简单的快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。不同隔离级别快照不同
- read committed :每次select都生成一个读快照
- repeatable read:开启事务后第一个select语句才是快照读的地方
- serializable :快照会退化为当前读,每次读取到的都是最新的记录
MVCC实现原理
记录中的隐藏字段
- DB_TRX_ID:(自增)最近修改事务ID,记录插入这条记录或者最后一次修改该记录的事务ID
- DB_ROLL_PTR:回滚指针,指向这一条记录的上一个版本,配合undo log,指向上一个版本
- DB_ROW_ID:隐藏主键,如果表结构没有主键,将会生成该隐藏字段
进入mysql文件目录,进入对应数据库目录,使用mysql提供的命令查看表结构,例如查看stu表空间文件:
ibd2sdi stu.ibd
在返回的columns中可见隐藏字段
undo log
- 回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。
- 当insert的时候,产生的undo log日志只在回滚时需要,当事务提交后,可被立即删除。
- 而当update、delete的时候,产生的undo log不仅在回滚时需要,在快照读时也需要,不会被立即删除。
undo log版本链
不同事务或者相同事务对同一条记录进行修改,会导致该记录的undolog生成一条记录版本链表,链表尾部是最早的旧记录。
readview
readview读视图,是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务( 未提交的)ID
readview中包含了四个核心字段(属性):
字段 | 含义 |
m_ids | 当前活跃的事务ID集合 |
min_trx_id | 最小活跃ID |
max_trx_id | 预分配事务ID,当前最大事务ID+1(因为事务ID是自增的) |
creator_trx_id | readView创建者的事务ID |
版本链数据访问规则:
不同的隔离级别,生成readview的时机不同:
READ COMMITTED: 在事务中每一次执行快照读时生成readView
REPEATABLE READ: 仅仅在事务第一次执行快照读时生成ReadView,后续复用该readview
RC隔离级别下的分析
在事务中每一次执行快照读时生成readView
例:当事务5中执行第一个查询语句时,查到的记录是蓝色框的记录。
从版本链头开始判断是否符合访问规则:
trx_id = 4 ,不符合第一条、第二条,符合第三条,不符合第四条。故需要找到上一个版本:
trx_id = 3,不符合第一条、第二条,符合第三条,不符合第四条。继续找上一个版本:
trx_id = 2,不符合第一条,但是符合第二条,故找到快照版本,事务5中第一条查询语句查询到的结果是该版本数据。
类似地,当事务5中执行第二个查询语句时,查到的记录是该版本数据:
RR隔离级别下的分析
仅仅在事务第一次执行快照读时生成ReadView,后续复用该readview
套用相同的规则,事务5第一次执行快照读和第二次执行快照读读到的数据都是该版本数据:
总结:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端