1. MVCC

概念:multi version concurrency control多版本并发控制 。MVCC 只在 REPEATABLE READ(可重复读) 和 READ COMMITTED(已读提交)这俩种隔离级别下适用

1.1. 当前读

给读操作加上共享锁、排它锁,DML 操作加上排它锁,这些操作就是当前读

  • 读取的数据记录,都是最新的版本,会对当前读取的数据进行加锁,防止其他事务修改数据,是悲观锁的一种实现
  • 如下操作都是当前读:
    • select lock in share mode(共享锁)
    • select for update(排他锁)
    • update (排他锁)
    • insert (排他锁)
    • delete (排他锁)
    • 串行化事务隔离级别

1.2. 快照读

普通的select id name user where id = 1;都属于快照读

  • MVCC实现
  • 快照读读到的数据不一定是最新版本的数据

1.3. 目的

  • 提供数据库读写性能,快照读,非当前读
  • 读写时无须竞争锁来提高性能

1.4. 数据库事务

  • 原子性由undo log实现
    • undolog 记录的是回滚日志,回滚指针指向了前一个是数据,根据回滚指针可以追溯到未变更前的所有数据形成了一个版本链
  • 持久性是由reod log实现(WAL写前日志)
  • 隔离性通过加索和MVCC实现
    • 写写操作,通过行锁/表锁实现
    • 写读操作,通过MVCC实现
  • ReadView介绍
    • 作用:在select时可以知道在版本链中选用哪条记录
    • 数据结构:
    • 如何判断版本链中哪个版本可用?
  • MVCC如何实现RC(读已提交)和RR(可重复读)
    • 读已提交生成ReadView的时机是每一次select语句时生成,所以访问的一定是最新的版本的,所以不能保证可重复读
    • RR生成ReadView的时机是以一个事务为单位的,RR可重复读会造成幻读,innodb是使用间隙锁锁住了区间,如查询>2的数据,则>2的数据都不会再插入来解决幻读

1.5. 实例

案例:需要支付一笔钱,两个人都登录进去了,这时候问题发生了

  1. 悲观并发控制PCC悲观锁(写多读少的并发环境下使用): 假设A正在访问并且发起了支付,那么A这条数据是已经锁定了的,悲观的以为一定会发生锁竞争,所以直接加锁。这就导致了B查询不到此条数据,需要等待到A访问完毕释放锁。 悲观锁保证在同一时间只能有一个线程访问,默认数据在访问的时候会产生冲突,然后在整个过程都加上了锁

  2. 乐观并发控制OCC乐观锁: 在A访问并且支付的时候,B也可以访问到数据。乐观锁认为在并发场景下,也不会产生冲突,所以也不会加锁。而是在数据提交时检测,如果有冲突则返回冲突信息

总结:Innodb 的 MVCC 机制就是乐观锁的一种体现,读不加锁,读写不冲突,在不加锁的情况下能让多个事务进行并发读写,并且解决读写冲突问题,极大的提高系统的并发性。


1.6. MVCC解决了什么问题

事务并发情况遇到的问题 点这详解

  • 脏读:读取到其它事务未提交的数据
  • 不可重复读:一个事务读取一条数据时,由于另一个事务修改了这条数据,导致读取前后数据不一致
  • 幻读:一个事务读取了某个范围数据的数量,另外的事务新增了这个范围的数据,再次读取发现得到结果不一致

MVCC 可以解决脏读,不可重复读,MVCC 使用快照读解决了部分幻读问题,但是在修改时还是使用的当前读,所以还是存在幻读问题,幻读的问题最终就是使用间隙锁解决。

1.6.1. MVCC实现三大要素

两个隐式字段、undo 日志、Read view


Copyright & copy lviter@163.com            updated 2024-02-06 09:54:56

results matching ""

    No results matching ""