在理解MVCC,我们需要先理解其他的知识点
(1)数据库为什么需要用事务?
为了保证数据存储过程中数据的最终一致性
(2)事务包含几种特征?
原子性、一致性、隔离性、持久性
(3)事务并发会存在哪些问题?
事务并发会出现脏读、不可重复读、幻读
(4)如何解决事务并发出现的问题?
设置事务隔离级别,读未提交,读提交,重复读,序列化
(5)事务通过什么实现事务的隔离性?
加锁
(6)加锁会带来哪些问题?
读的时候无法写,写的时候无法读,同时降低了数据库的性能
(7)数据库是如何实现加锁以后带来的性能问题?
使用MVCC多版本并发控制,可以解决读时可以修改,更新时候可以读
=====================================================================
MVCC如何实现的?
这时候我们需要了解下面几个问题:
第一个:什么是MVCC
MVCC是在并发访问数据库时,通过对数据做多版本管理,避免因为写锁的阻塞而造成读数据的并发堵塞问题。
总之:就是MVCC是通过保存数据的历史版本,根据比较版本号来处理数据是否显示,从而达到读取数据的时候不需要加锁就可以保证事务隔离性的效果。
第二:MVCC实现的核心点有哪些?
1:事务的版本号
2:表的隐藏列
3:undo log
4:read view
解析上述核心点:
事务版本号:每次事务开启前会从数据库获取一个自增长的事务id,可以从事务id判断事务的执行先后顺序
表的隐藏列:
DB_TRX_ID:记录操作该数据事务的事务id;
DB_ROLL_PTR:指向上一个版本数据在undo log里的位置指针
DB_ROW_ID:隐藏ID,当创建表没有合适的索引作为聚集索引时,会用该隐藏ID创建聚集索引
undo log:主要是记录数据修改之前的日志,在表信息修改之前先把数据拷贝到undo log,当事务进行回滚时可以通过undo log里的日志进行数据还原。
undo log的用途:
1:保证事务进行rollback时的原子性和一致性,当事务进行回滚的时候可以用undo log 的数据进行恢复
2:用于MVCC快照读的数据,在MVCC多版本控制中,通过读取undo log的历史版本数据可以实现不同事务版本号都拥有自己独立的快照数据版本;
事务版本号、表隐藏列、undo log的关系?
(1)准备一张原始数据表user_info
(2)开启事务A:对user_info表进行update user_info set name = “李四” where id = 1
进行如下操作:
1:首先获取一个事务编号104
2:把user_info表修改前的数据copy到undo log
3:修改user_info 表的id =1的数据
4:把修改后的数据事务版本号修改当前事务版本号,并把DB_ROLL_PTR地址指向undo log 数据地址
最后执行完结果如图:
read view
在innodb 中每个SQL语句执行前都会得到一个read_view。副本主要保存了当前数据库系统中正处于活跃(没有commit)的事务的ID号,其实简单的说这个副本中保存的是系统中当前不应该被本事务看到的其他事务id列表