Mysql MVCC精简

MVCC

Multi Version Concurrent Controller,多版本并发控制。

它的作用是多个事务并发读写时不互斥,并解决脏读与不可重复读的问题。应用在RC和RR隔离级别下

我们首先需要了解两个内容:undo log组成的版本链、read view 一致性视图。

undo log版本链:我们知道在进行更新操作时,首先会生成一个Undo log ,然后再去内存中更新数据。当事务提交之后,mysql会保留修改前的Undo log日志,这个时候还会维护两个隐藏字段:trx_id事务idroll_pointer 回滚指针,通过这两个字段把Undo log日志串联起来形成一个历史记录版本链

如下图所示:

Mysql MVCC精简_第1张图片

read view:将当前所有未提交的事务id存到一个集合中,还会保存当前最大的事务id。假如当前有三个事务id分别为100 、200、300,其中300的事务已经提交了,这个时候生成的read view就是:[100,200],300

MVCC 就是从数据库中读取最新的数据,然后从这行数据对应的undo log中拿到当前事务id,拿这个事务id去read view中根据一种可见性分析算法来判断,最终找到当前事务能够读取到的数据。

我们可以把read view中的事务id分为三个部分,如下图所示第一个部分是小于当前未提交的最小事务id,也就是绿色部分,这部分的事务都是已经提交了的事务;第二部分就是当前未提交的最小事务id与最大事务id,这就是黄色部分,这个区间的事务id可能已经提交了,也可能没有提交;第三部分是大于最大事务id的区间,也就是红色部分,这部分的数据是未开始的事务。

Mysql MVCC精简_第2张图片

  • 如果事务id < Min_id,那么就表示这个事务已经提交了,对于当前事务来说数据是可见
  • 如果事务id > Max_id,那么就表示这个事务是在read view之后新开始的事务,对于当前事务是不可见的。若trx_id是当前事务id那么是可见
  • 如果事务id在[Min_id,Max_id]这个区间中就要分情况讨论了
    • 如果事务id在生成read view时,并在收集到未提交事务id的集合中,那么对于当前事务是不可见
    • 如果事务id不在read view之前未提交事务id的集合中,那么对于当前事务是可见的。

可重复读隔离级别下,一个事务中,在第一次查询时,就会生成一个read view,之前再进行各种操作read view都不会改变,直到事务结束。这样就保证了可重复读,并解决了大部分的幻读问题。

在可重复读隔离级别下,一个事务中每一次select查询时,都会生成一个新的read view,这样也就保证了每一次读取到的数据的都是其他事务已经提交的数据,避免脏读。

update操作时,它会直接使用最新的数据来进行更新,并在undo log记录中记录当前是事务id。对于删除的情况可以认为是update的特殊情况,会将版本链上最新的数据复制一份,然后将trx_id修改成删除操作的trx_id,同时在该条记录的头信息(record header)里的(deleted_flag)标记位写上true,来表示当前记录已经被删除,在查询时按照上面的规则查到对应的记录如果delete_flag标记位为true,意味着记录已被删除,则不返回数据。

注意:

Mysql并不是在执行begin/start transaction开启事务语句时生成的事务id,而是整个事务中第一次执行更新操作或加排他锁操作的语句时,事务才会真正生成,才会生成真正的事务id。mysql内部是严格按照事务的启动顺序来分配事务id的。我们也就能知道事务id是递增的

你可能感兴趣的:(报班总结笔记,mysql,数据库,java)