sql mvcc机制
什么是当前读、快照读?
当前读
当前读指的是读取数据的最新提交版本
- select lock in share mode
- select for update
- insert
- update
- delete
底层都是通过加锁实现的
快照读
快照读指的是读取数据在某个时间点的快照(版本),而不是数据的最新版本
普通selcet语句,底层就是利用mvcc机制实现的
MVCC是什么?
多版本并发控制:
多版本:指mysql维护着行数据的多个版本
并发控制:在多个事务同时操作某一行记录时,mysql控制返回 多个版本的行记录中 的某个版本
用来解决什么问题?
用来解决读写冲突问题。
数据库(普通select语句)并发事务时会出现脏读、不可重复读、幻读问题,因此利用mvcc机制来解决。
流程:
一条select语句来查询数据,但是查询的数据有多个版本,这时就要选择其中的某一个版本返回
数据隔离级别和并发问题
脏读 (Dirty Read)、不可重复读 (Non-Repeatable Read) 和 幻读 (Phantom Read) 是数据库事务并发执行时,在没有采取足够隔离措施的情况下,会产生的三类典型问题。
mvcc机制实现了隔离级别,可以解决这三类并发问题
脏读
要解决脏读,就得上读已提交的隔离级别
得保证一个事务只能读取到其他事务已经提交的数据,没提交的就不该读取到
不可重复读
解决不可重复读问题,就得上读已提交隔离级别
一个事务第一次读取之后,后面读取得每一次数据都应该和第一次读取的一样
那就得维护一份数据的多个版本
每个事务修改一次就生成一个新版本,让不同事务读取不同的版本
在读已提交的得隔离级别下,让事务去读已经提交的数据版本,就可以避免脏读
在不可重复读的隔离级别下,让事务每次读到同一个版本的数据,这样每次读到的都是一样的了,就避免的不可重复读的问题
把修改的数据版本记录到undo log中,给表加一个隐藏字段,叫回滚指针
回滚指针指向undolog日志,日志记录了该表的修改记录的各个版本
利用回滚指针将历史版本串联成一个列表,想读哪个,查找即可
那一个事务来查数据,怎么知道要查哪个版本的数据呢?
所以要为每个事务分配一个id,事务id自增分配。通过对比事务id的大小,就知道哪个事务创建的早、哪个晚,记录哪些事务提交了,哪些未提交,让提交的早的事务不要看提交的比较晚的数据即可。所以要给表加上隐藏字段修改数据的事务id,谁修改了这条数据,就把对应的事务id记录下来
readview:4个重要字段:比较复杂,利用数轴来看
记住作用:就是决定在多个版本中,到底该读哪一个版本
undolog记录数据版本
readview去判断这个数据版本对当前事务的可见性
MVCC怎么实现的?
隐藏字段、undolog版本链、readview
undolog版本链、readview是怎么回事?
四种隔离级别怎么实现的
读未提交怎么实现?
不用管
串行化:加锁
可重复读怎么实现?(复用readview和mvcc机制)
可重复读会在第一次select时生成一个readview,通过readview判断应该读哪个数据
读已提交怎么实现?
每次select时就会生成一个新的readview