概述
目录
MVCC
当前读和快照读
隐藏字段
mvcc-undolog
readview
实现原理
MVCC
基本概念
MVCC全称是Multi-Version Concurrency Control(多版本并发控制),是一种并发控制的方法,通过维护一个数据的多个版本,减少读写操作的冲突。
如果没有MVCC,想要实现同一条数据的并发读写,还要保证数据的安全性,就需要操作数据的时候加读锁和写锁,这样就降低了数据库的并发性能。
有了MVCC,就相当于把同一份数据生成了多个版本,在操作的开始各生成一个快照,读写操作互不影响。无需加锁,也实现数据的安全性和事务的隔离性。
事务的四大特性中隔离性就是基于MVCC实现的。
MVCC只在 读已提交 和 可重复读 两个隔离级别下起作用,因为 读未提交 隔离级别下,读写都不加锁, 可串行化 隔离级别下,读写都加锁,也就不需要MVCC了。
当前读和快照读
先普及一下什么是当前读和快照读。
当前读: 读取数据的最新版本,并对数据进行加锁。
例如:insert、update、delete、select for update、 select lock in share mode。
快照读: 读取数据的历史版本,不对数据加锁。
例如:select
MVCC是基于Undo Log、隐藏字段、Read View(读视图)实现的。
-
隔离级别-读已提交:每次select,都生成一个快照读。
-
隔离级别-可重复读(ino默认):开启事务后第一个select语句才是快照读的地方。
-
隔离级别-串行化:快照读会退化为当前读。
隐藏字段
一个表结构除了自己创建的字段,InnoDB还会自动的给我们添加三个隐藏字段及其含义分别是:
隐藏字段 | 含义 |
---|---|
DB_TRX_ID | (最近一次提交事务的ID):修改表数据时,都会提交事务,每个事务都有一个唯一的ID,这个字段就记录了最近一次提交事务的ID。 |
DB_ROLL_PTR | (上个版本的地址):修改表数据时,旧版本的数据都会被记录到Undo Log日志中,每个版本的数据都有一个版本地址,这个字段记录的就是上个版本的地址。 |
DB_ROW_ID | 隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。 |
前两个字段是肯定会添加的, 最后一个字段DB_ROW_ID,得看当前表有没有主键。
mvcc-undolog
回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。
当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除。
而update、delete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。
最终我们发现,不同事务或相同事务对同一条记录进行修改,会导致该记录的undolog生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。
readview
//快照读在读的时候,读取哪个版本链上的历史记录,又readview决定
ReadView(读视图)是 快照读 SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。
ReadView中包含了四个核心字段:
字段 | 含义 |
---|---|
m_ids | (当前未提交的事务id)当前活跃的事务ID集合 |
min_trx_id | 最小活跃事务ID |
max_trx_id | 预分配事务ID,当前最大事务ID+1(下一个事务的id,因为事务ID是自增的) |
creator_trx_id | ReadView创建者的事务ID |
而在readview中就规定了版本链数据的访问规则:
trx_id 代表当前undolog版本链对应事务ID。
不同的隔离级别,生成ReadView的时机不同:
-
读已提交:在事务中每一次执行快照读时生成ReadView。
-
可重复读:仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。
实现原理
通过readview中维护的四个属性决定当前事务能读到哪个版本的数据,从表记录到Undo Log历史数据的版本链,依次匹配,满足哪个版本的匹配规则,就能读到哪个版本的数据,一旦匹配成功就不再往下匹配。
最后
以上就是纯情台灯为你收集整理的MySQL的MVCC实现原理的全部内容,希望文章能够帮你解决MySQL的MVCC实现原理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复