目录

什么是MVCC?🌸

为什么需要MVCC

普及一下常见锁🔒(知道可以跳过)

MVCC适用于的事务隔离级别

MVCC实现原理✔

 undo日志

执行流程如下


什么是MVCC?🌸

MVCC,全称 Multi-Version Concurrency Control ,即多版本并发控制。mvcc,它是一种并发控制方法,一般在数据库管理系统中,实现数据库的并发访问,在编程语言中实现事务内存。

总结:主要为了提升并发性能

为什么需要MVCC

  • 数据库原生的锁

        最原生的锁,锁住一个资源后会禁止其他任何线程访问同一个资源。但是很多应用的一个特点都是读多写少的场景,很多数据的读取次数远大于修改的次数,而读取数据间互相排斥显得不是很必要。

  • 读写锁的出现

        读锁和读锁之间不互斥,而写锁和写锁、读锁都互斥。这样就很大提升了系统的并发能力。之后人们发现并发读还是不够

  • mvcc概念出现

        能不能让读写之间也不冲突的方法,就是读取数据时通过一种类似快照的方式将数据保存下来,这样读锁就和写锁不冲突了,不同的事务session会看到自己特定版本的数据。当然快照是一种概念模型,不同的数据库可能用不同的方式来实现这种功能

总结:

MVCC 就是因为大佬们,不满意只让数据库采用悲观锁这样性能不佳的形式去解决读-写冲突问题,而提出的解决方案,所以在数据库中,因为有了 MVCC,所以我们可以形成两个组合:

  •     MVCC + 悲观锁

    MVCC解决读写冲突,悲观锁解决写写冲突

  •     MVCC + 乐观锁

    MVCC 解决读写冲突,乐观锁解决写写冲突

普及一下常见锁🔒(知道可以跳过)

读锁:也叫共享锁、S锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S 锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

写锁:又称排他锁、X锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。

表锁:操作对象是数据表。Mysql大多数锁策略都支持,是系统开销最低但并发性最低的一个锁策略。事务t对整个表加读锁,则其他事务可读不可写,若加写锁,则其他事务增删改都不行。

行级锁:操作对象是数据表中的一行。是MVCC技术用的比较多的。行级锁对系统开销较大,但处理高并发较好。

MVCC适用于的事务隔离级别

MVCC只在 READ COMMITTED (读取已提交) 和 REPEATABLE READ (可重复读) 两个隔离级别下工作。其他两个隔离级别够和MVCC不兼容, 因为 READ UNCOMMITTED (读取未提交) 总是读取最新的数据行, 而不是符合当前事务版本的数据行。而 SERIALIZABLE (可串行化) 则会对所有读取的行都加锁。

MVCC实现原理

MVCC的目的就是多版本并发控制,在数据库中的实现,就是为了解决读写冲突,它的实现原理主要是依赖记录中的 3个隐式字段undo日志Read View 来实现的。

3个隐式字段

DB_TRX_ID, DB_ROLL_PTR, DB_ROW_ID

简单来说:第一个事务id(每处理一次加一) ,第二个是指向undolok的一个指针 ,第三个是用于存在聚集索引中的id

 比如:

 DB_ROW_ID 是数据库默认为该行记录生成的唯一隐式主键,DB_TRX_ID 是当前操作该记录的事务 ID ,而 DB_ROLL_PTR 是一个回滚指针,用于配合 undo日志,指向上一个旧版本

 事务A:对数据进行了修改(将name中的张三改为李四)

  • 第一步:用排他锁锁定这一条记录

        

  •  第二步:UNDOLOG会记录日志,作为旧记录,既在 undo log 中有当前行的拷贝副本

  •  第三步:将回滚指针的值copy到UNDOLOG中

        

  •  第四步:修改当前的name值并且修改隐藏字段的事务 ID 为当前事务 1的 ID, 我们默认从 1 开始,之后递增,回滚指针指向拷贝到 undo log 的副本记录,既表示我的上一个版本就是它

        

 事务B:事务A修改但未提交,同时对事物B也对该行数据做了修改

        

 首先会看到有两个对改行修改的数据,

 undo日志

  • insert undo log

代表事务在 insert 新记录时产生的 undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃

  • update undo log

事务在进行 updatedelete 时产生的 undo log ; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被 purge 线程统一清除
在不考虑redo log 的情况下利用undo log工作的简化过程为:

 1)为了保证数据的持久性数据要在事务提交之前持久化

  2)undo log的持久化必须在在数据持久化之前,这样才能保证系统崩溃时,可以用undo log来回滚事务

执行流程如下:

一、比如一个有个事务插入 persion 表插入了一条新记录,记录如下,name 为 小明 , age 为 10 岁,隐式主键是 1,事务 ID回滚指针,我们假设为 NULL

 二、 现在来了一个事务 1对该记录的 name 做出了修改,改为 小红

  • 事务 1修改该行(记录)数据时,数据库会先对该行加排他锁
  • 然后把该行数据拷贝到 undo log 中,作为旧记录,既在 undo log 中有当前行的拷贝副本

  • 拷贝完毕后,修改该行name为小红,并且修改隐藏字段的事务 ID 为当前事务 1的 ID, 我们默认从 1 开始,之后递增,回滚指针指向拷贝到 undo log 的副本记录,既表示我的上一个版本就是它

 

  • 事务提交后,释放锁

 

Logo

华为云1024程序员节送福利,参与活动赢单人4000元礼包,更有热门技术干货免费学习

更多推荐