当前位置: 首页 > 科技观察

一篇文章看懂整个MVCC

时间:2023-03-16 11:51:03 科技观察

1。什么是MVCMVCC,全称是Multi-VersionConcurrencyControl,即多版本并发控制。它是一种并发控制的方法。一般用于数据库管理系统,实现对数据库的并发访问。比如MySQLInnoDB,主要目的是提高数据库的并发性能,不加锁,非阻塞并发读。MVCC多版本并发控制是指维护一个数据的多个版本,使得读写操作不冲突。快照读是MySQL实现MVCC的非阻塞读功能。2、要解决的问题是什么?1、三种数据库并发场景:读读:不会有问题,不需要并发控制。幻读、不可重复读写:存在线程安全问题,可能存在更新丢失问题。2.解决问题。MVCC是一种用于解决读写冲突的无锁并发控制,即给事务分配一个单增的时间戳。每次修改保存一个版本,版本与事务时间戳关联,读操作只读取事务开始前(隔离级别RC下)数据库的快照,所以MVCC为数据库解决了以下问题:当并发读写数据库,可以实现读操作不需要阻塞写操作,写操作不需要阻塞读操作,提高了并发读写的性能数据库,解决了脏读、幻读、不可重复读等事务隔离问题,但无法解决丢失更新的问题。实现原理主要看record、undolog、readview中的三个隐藏字段。1、隐藏字段对于每一行记录,除了我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID等字段:DB_ROW_ID:6字节,隐藏主键,如果数据表没有有一个主键,那么innodb会自动生成一个6字节的row_idDB_TRX_ID:6字节,最近修改的事务id,记录创建这条记录或者最后修改记录的事务idDB_ROLL_PTR:7字节,回滚指针,用来配合undolog,指的是之前老版本的假设记录,如图:2.undolog1)概念回滚日志,意思是插入、删除、更新操作时产生的便于回滚的日志。2)说明执行insert操作时,产生的undolog仅在事务回滚时使用,事务提交后可立即丢弃。在执行update和delete操作时,产生的undolog不仅在事务回滚时需要,在读取快照时也需要,所以不能随便删除,只有当日志不涉及快照读取或事务回滚时才可以.相应的日志会被purge线程统一清除。更新和删除数据时,实际上设置了旧记录的deleted_bit,并没有删除过时的记录,因为innodb为了节省磁盘空间,有专门的purge线程来清除deleted_bittrue记录,如果一个记录的deleted_id为真,并且DB_TRX_ID对purge线程的读视图可见,则可以清除这条记录。3)undolog生成的记录链表(1)假设有一个事务号为1的事务往表中插入一条记录,那么此时行数据如下,主键id=1,事务id=1(2)假设有第二个事务(2号)修改记录名,改成lisi底层操作:当事务2修改行记录数据1时,给数据行2加排它锁,复制行数据到undolog,作为旧记录3.修改行名lisi,修改事务id=2,回滚指针指向复制到undolog的复制记录4.提交事务,释放锁。(3)假设有第三个事务(编号3)修改了记录的年龄,改为32。底层操作:当事务3修改了这一行的记录数据时1.加排它锁datarow2.将这一行的数据作为旧记录复制到undolog中。如果发现该行的记录已经有undolog,则将最新的旧数据作为链表的头部,插入到该行记录的undolog的顶部3.修改该行的age为32岁,并修改事务id=3,回滚指针指向刚才复制的undolog的复制记录4.提交事务,释放锁。.从上面这一系列图可以发现,不同事务或者同一个事务对同一条记录的修改,都会导致记录的undolog生成一个记录版本链表。undolog的头部是最新的旧记录,表尾是最早的。旧记录。3.读视图ReadView是事务执行快照读操作时产生的读视图。在事务执行快照读取的那一刻,系统会生成此刻的快照,记录并维护此刻活跃事务在系统中的id,用于可见性,也就是说,当一个事务是执行一次快照读取,为记录创建一个ReadView视图,作为条件判断当前事务能看到的是哪个版本的数据,有可能读取到最新的数据就是最新的数据,并且也可以读取当前行记录的undolog中某个版本的数据。1)可见性算法在待修改数据的最新记录中取出DB_TRX_ID(当前交易id),与系统内其他活跃交易的id进行比较。如果DB_TRX_ID与ReadView的属性进行比较,不满足可见性,则使用DB_ROLL_PTR回滚指针取出undolog中的DB_TRX_ID进行比较,即遍历链表中的DB_TRX_ID,直到找到满足条件的DB_TRX_ID。DB_TRX_ID所在的旧记录就是当前交易能看到的数据。2)visibilityrule首先需要知道ReadView中的三个全局属性:trx_list:用于维护ReadView生成时系统的活跃事务ID(1,2,3)的值列表。up_limit_id:记录trx_list列表中交易ID最小的ID(1)low_limit_id:当ReadView产生时,系统要分配的下一个交易ID(4)具体比较规则如下:先比较DB_TRX_ID=low_limit_id是否大于等于,说明DB_TRX_ID所在的记录是在ReadView生成后才出现的,那么对当前交易是不可见的;如果小于则进行下一步判断。确定DB_TRX_ID是否在活动事务中。如果trx_list包含DB_TRX_ID,则表示在生成ReadView时事务仍然处于活动状态。当前事务看不到未提交的数据。如果不包含它,则表示该事务处于读取视图中。在生成View之前commit已经开始了,所以可以看到修改后的结果。流程图如下:总结:分两种情况,可以看出DB_TRX_ID