1.什么是mvcc(解决读写冲突,写的都是最新版本)
问题:如果有人从数据库中读数据的同时,有另外的人写入数据,有可能读数据的人会看到【半写】或者不一致的数据。
解决:1)通过加锁,让所有的读者等待写者完成工作,但是效率会非常的差
2)利用mvcc,mvcc使用了一种不同的手段,每个连接到数据库的读者,在某个瞬间看到的是数据库的一个快照,写着写操作造成的变化在写操作完成之前(数据库事务提交之前)对于其他的读者来说是不可见的。(这里可以想象为git,我和别人在一个库中,别人在没有push之前我的界面看到的是之前的版本,也就是之前的快照),所以mvcc数据库更新一条数据的时候,新数据不会直接覆盖旧数据,而是将旧数据标记为过时(我的理解为一个版本),读者读到的是已经提交的最新的版本。
优点:mvcc避免了填充删除操作在内存和磁盘存储结构造成的空洞的开销,但是需要系统周期性整理,以真正删除老的、过时的数据。
mvcc提供了时点一致性视图。mvcc并发控制下的读事务一般使用时间戳或者事务ID去标记当前的数据库的状态(版本),读和写事务相互隔离,不需要加锁
总结:一句话讲,MVCC就是用 同一份数据临时保留多版本的方式 的方式,实现并发控制
Mysql会在表中添加2个隐藏的字段,DB_TRX_ID(插入或者更新行的最后一个事务的ID)(就是第几个版本为后面的回滚做准备) 和 DB_ROLL_PTR (回滚指针)。每开始新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询每行记录的版本号进行比较。回滚指针用来查找历史版本的数据。
2.当前读和快照读
当前读:就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁
快照读:不加锁的select操作就是快照读,快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读,快照读的实现是基于多版本并发控制的,即mvcc,快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本
1.1.1. MVCC识别规则
当执行查询sq|时会生成一致性视图read-view, 它由执行查询时所有未提交事务id数组(数组里最小的id为min id)和已创建的最大事务id (max id)组成,查询的数据结果需要跟read-view做比对从而得到快照结果。
版本链比对规则:
1.如果落在绿色部分( trx jid
2.如果落在红色部分( trx id>max. id),表示这个版本是由将来启动的事务生成的,是肯定不可见的;
3.如果落在黄色部分(min. id
a.若row的trx_ id在数组中,表示这个版本是由还没提交的事务生成的,可见,当前自己的事务是可见的;
b.若row的trx. id不在数组中,表示这个版本是已经提交了的事务生成的,可见。
对于删除的情况可以认为是update的特殊情况,会将版本链上最新的数据复制-份,然后将trx. id修改成删除操作的trx_ id,同时在该条记录的头信息(record header)里的(deleted_ flag)标记位写上true,来表示当前记录已经被删除,在查询时按照上面的规则查到对应的记录。如果delete flag标记位为true, 意味看记录已被删除,则不返回数据。
图解