刚学完mysql的MVCC(多版本并发控制),记录一下
个人笔记,内容比较随意。
可能存在有错误的地方,欢迎指正
既然谈到MVCC,就一定要说MySQL日志系统中的一种:undo log日志,这里不对undo log做详细描述。
在Innodb的存储引擎中,有两个隐藏列,分别是:trx_id、roll_pointer(回滚指针)。
trx_id表示的是独一无二事务id,是一个全局的自增变量。
roll_pointer是标记每次修改的版本,通过roll_pointer将每次修改的数据连接起来.roll_pointer存储的是旧数据的地址
接下来说MVCC
Innodb下有两种读,分别是:当前读和快照读,MVCC主要是通过快照读实现
快照读会产生【读视图】(ReadView),在该事务执行快照读的那一刻,就会产生一个当前数据库系统的快照
ReadView主要有四个属性:
m_ids:生成该readview时,当前系统中【活跃的事务】id列表。
min_trx_id:当前系统【活跃事务】中最小的【事务id】
max_trx_id:当前系统中计划分配给下一个事务的id,他可能是m_ids的最大值+1,也可能比他大
creator_trx_id:生成这个readView的事务id
【活跃的事务】:个人理解就是未提交的事务
如果【被访问数据的事务trx_id】和readView中的【creator_trx_id值】相同,意味着自己在访问自己修改过的记录,可以被访问。
如果【被访问数据的事务trx_id】小于readView中的【min_trx_id】值,说明生成这个版本数据的事务,在生成readview前已经提交,这样的数据也可以访问。
通俗一点:这个数据之前被其他的事务修改过,但是事务已经提交,所以这个版本的数据是可以使用的,这样不会产生脏读。
如果【被访问数据的事务trx_id】大于等于readView中的max_trx_id值,说明生成这个版本数据的事务,是在生成readview后开启,这样的数据不应该被访问。
如果【被访问数据的事务trx_id】如果在min_trx_id和max_trx_id范围内,则需要判断是不是在【m_ids】中(目的是判断这个数据是不是已经提交)。如果在,说明生成这个版本的事务还是活跃的,没有提交的事务产生的数据当然不能读,如果不在,说明事务已经提交,该数据可以被访问
MVCC如何解决脏读
脏读就是在同一事务内,读取了其他事务没有提交的数据。通过readView进行版本选择,可以有效的解决脏读。
RC隔离级别与RR隔离级别在MVCC上的区别
RC隔离级别没有解决不可重复读,RR隔离级别解决了不可重复读。造成二者差异的原因就是在对ReadView生成方式上的不同。
【同一事务中】RC隔离级别在每次读取数据的时候,都会生成一个ReadView,如果在两次读取的间隔时间,有事务提交,那两次生成的ReadView就会不一致,这也是导致RC隔离级别没有解决的不可重复读的原因。
【同一事务中】RR隔离级别,只在第一次读取数据的时候生成一个ReadView,之后整个事务中,一直使用该ReadView,就能保证在同一事务中,多次读取到的数据是一致的。