MVCC详解以及原理
解决什么问题(概念):
数据库并发的场景:
读-读:不存在并发,不需要进行控制
读-写:可能会造成事务隔离性问题,产生脏读/幻读/不可重复读(mvcc主要解决此问题)
写-写:线程之间冲突,可能会造成数据错误
mvcc是数据库的多版本并发控制,是为了提高数据库的并发性能,用更好的方式去处理读-写冲突,做到存在读写冲突的时候,也能做到不加锁,非阻塞并发读。
通过什么方式实现的(原理):
mvcc模型主要是通过3个隐藏字段,undo日志,Read View等实现的。
隐藏字段:
DB_TRX_ID 记录最后一次修改记录的事务ID
DB_ROLL_PTR 回滚指针,执行这条记录的上个版本
DB_ROW_ID 如果数据表没有主键,innodb会自动生成隐藏主键
undo日志(回滚日志)
主要分为两种类别的日志:insert log 和 update undo lo
Insert undo log 代表事务在insert 新纪录时产生的undo log,只在事务回滚的时候才会需要,事务提交之后就可以废弃掉
Update undo log 事务在进行update和delete时产生的undo log;不仅在事务回滚的时候需要,快照读的时候也是需要的,所以不能随意进行删除,会被purge线程统一删除。
Read View
当事务开始执行的时候,会给每个事务生成一个ReadView。这个ReadView会记录4个非常重要的属性
- create_trx_id 当前事务的id
- m_ids 当前系统中所有活跃的事务id,活跃事务是指当前系统开启了事务,并未提交的事务
- min_trx_id 当前系统中,事务id最小的事务
- max_trx_id 当前事务中最大的事务id再加1,也就是系统中下一个要生成的事务id
当一个事务读取某条数据时,就会按照如下规则来决定当前事务能读取到什么数据:
- 如果当前数据的row_trx_id小于min_trx_id,那么表示这条数据是在当前事务开启之前,其他事务就已经将该条数据修改了并提交了事务,所以当前事务可以读取到数据。
- 如果当前数据的row_trx_id大于max_trx_id,那么表示再当前事务开启以后,系统中有新的事务开启了,并且新的事务修改了这行数据并且提交了事务,所以当前事务肯定是不能读取到的。
- 如果当前数据的row_trx_id处于min_trx_id和max_trx_id的范围之内,row_trx_id在m_ids中,那么当前事务不能读取到,row_trx_id在m_ids中表示的是和当前事务在同一时刻开启的事务,修改了数据的值,并且提交了事务,所以不能让当前事务读取到。