• MVCC


     什么是MVCC?

      MVCC(Multiy Version Concurrent Control),即多版本并发控制,是一种乐观锁的实现。

      MVCC使得读不会加锁,提高了数据库的并发处理能力。通过MVCC,MySQL可以实现【读已提交】和【可重复读】等隔离级别,保证了隔离性。

     MVCC原理:

      同一份数据临时保存多个版本的一种方式, 是通过undo log来实现的。

      不同的事务可以读取到不同版本的数据,从而解决脏读和不可重复读的问题

      即根据事务开始的时间不同,不同的事务对同一张表,同一时刻看到的数据可能是不一样的。但是对每个事务来说,在它的执行期间,不管它执行多长时间,它看到的数据都是一致的。

      

     InnDB中的MVCC:

      InnoDB中每个事务都有一个唯一的事务ID,即为transaction_id。它是在事务开始时向InnoDB申请,按照时间先后严格递增。

      每行数据有多个版本,是依赖undo log 来实现的。

      每次事务更新数据就会生成一个新的数据版本,并把transaction_id记为 row_trx_id,同时,旧的数据版本会保留在undo log中,而且新的版本会记录旧版本的回滚指针,通过它直接拿到上一个版本。

      所以,InnoDB中的MVCC其实是通过在每行记录后面保留两个隐藏的列来实现的。一列是事务ID:trx_id ; 另一列是回滚指针:roll_pt 。

     undo log :回滚日志

        记录事务修改之前的数据的一个版本,可以用于回滚。同时提供MVCC下的读,也即是非锁定读。

        根据操作的不同,undo log分为两种:insert undo log 和 update undo log。

        1) insert undo log 

        insert 操作产生的undo log,因为insert 操作记录没有历史版本只对当前事务本身可见,对于其他事务此记录不可见。所以insert undo log可以在事务提交后直接删除而不需要进行purge操作。

        purge:主要任务是将数据库中已经 mark del 的数据删除,另外也会批量回收 undo pages。

        2)update undo log

        update和delete删除产生的undo log都属于同一类型,update可以视为insert 新数据到原位置,delete旧数据,undo log 暂时保留旧数据。

        多个事务都更新某条记录的时候,都会把旧的记录数据保存到undo log日志中。因此undo log日志中会存在同一条数据的多条记录的的情况。这也就是同一条记录在数据库中存在多个版本,也就是MVCC。

     read-view(视图)

      read-view是InnoDB在实现MVCC时用到的一致性视图,用于支持【读已提交】以及 【可重复读】隔离级别的实现。

      read-view 不是真实存在的,只是一个概念,undo log才是它的体现。它主要是通过版本和undo log计算出来的,作用是决定事务能看到哪些数据。

      

      问题:当一个新的事务开启后,一个比当前事务id小的事务进行了数据修改提交,那么,当前事务可以读取到比自己事务id小的事务的修改后的最新数据吗?

      要回答这个问题,请继续往下看:

      

      每个事务或语句有自己的一致性视图,普通查询语句是一致性读,一致性读会根据row trx_id和一致性视图确定数据版本的可见性。   

      数据版本的可见性规则:

      read-view 中主要包含当前系统中还有哪些活跃的读写事务,在实现上InnoDB为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前正在活跃(还未提交的事务) 。

      

       规则如下:

        ①:事务创建时,已提交的事务对当前事务可见

        ②:事务创建时,未来开启的事务对当前事务不可见

        ③:事务创建时,对于早于当前创建的事务,如果在当前事务创建视图后提交,不可见;若在当前事务创建视图前提交,可见。

     快照读和当前读

      事务的更新操作,是先读后写,这个读是查询的数据行的最新数据。而在事务中的查询语句的读,是从历史版本中查询的,叫做快照读。

      1、快照读

        查询当前事务可见的历史版本中的数据

      2、当前读

         事务对记录更新操作,读取到的表中数据的最新值。然后执行更新操作,因为不可能去更新历史版本中的数据,可能已有其他事务先更新了。

     select当前读

      除了查询语句外,select语句如果加锁也是当前读。

      加锁方式如:lock in mode 或 for undate

      如:

      select age from t where id=2 lock in mode.

      select age from t where id=2 for update.

     什么是幻读?

      指的是当某个事务在读取某个范围内的记录时,会产生幻行,即两次读取的数据行不一致。

      原因是,一个事务先读取了某个范围的数量,同时,另一个事务新增了这个范围的数据,再次读取发现两次读取的结果不一致。

      MVCC使用快照读解决了部分幻读问题,但是在修改时还会存在幻读问题,幻读最终是通过间隙锁解决的。

     什么是间隙锁?

      间隙锁是可重复读级别下才会有的锁,结合MVCC和间隙锁可以解决幻读问题。

      间隙锁(GAP LOCK):当我们使用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁,对于键值在条件范围内但并不存在的记录,叫做间隙(GAP),InnoDB也会对这个间隙加锁,这种锁机制叫做间隙锁。

        如:user表中存在id为1,3,4,5,6的5条记录,那么这个SQL:

        update user set score=’x‘ where id<6; 

        这条sql使用的是范围作为条件,InnoDB分为会为这条sql加排他锁。不仅对符合条件的记录加了锁,对不存在的记录,id为2的间隙也会加锁。这时候如果插入一条id为2的记录就会阻塞。这就是间隙锁。

      //////////////////////////////////////////////////////////// 旧的笔记,仅供参考  START ////////////////////////////////////////////////////////////////

      InndoDB拥有一个自增的全局事务ID,每开启一个新的事务,全局事务ID自增1,并且在事务中都会记录当前事务的唯一ID,也称为事务版本号。

      InnoDB的MVCC是通过在每行记录后面保存两个隐藏的列来实现的。一列保存了创建行 的事务的事务版本号,一列保存了删除行的事务的事务版本号

      下面是可重复读隔离级别下,InnoDB实现MVCC的具体操作:

      SELECT:InnoDB只查找创建版本号小于等于当前事务版本号 且  删除版本号为空,或者大于当前事务版本号 的记录。

           这样可以确保事务读取的行,要么在事务开始前已经存在的,要么是事务自身新增或修改过的

      INSERT:InnoDB为新插入的每一行保存当前事务版本号作为行版本号

      DELETE:InnoDB为删除的每一行保存当前事务版本号作为删除版本号

      UPDATE:删除原来的行插入当前事务版本号作为删除版本号,并插入一条新的记录,保存当前事务版本号作为行版本号

      //////////////////////////////////////////////////////////// 旧的笔记,仅供参考  END ///////////////////////////////////////////////////////////////////

    END.

  • 相关阅读:
    fiximulator
    Maven POM 模板[z]
    Sentinel 实战-控制台篇[z]
    Sentinel 实战-限流篇[z]
    RPC 框架
    如何手写实现简易的Dubbo[z]
    降级、熔断、限流[z]
    Transfix
    Memcached和Memcache安装(64位win7)[z]
    Oracle分区表例子
  • 原文地址:https://www.cnblogs.com/yangyongjie/p/14644896.html
Copyright © 2020-2023  润新知