数据库InnoDB-MVCC-多版本并发控制

数据库InnoDB-MVCC-多版本并发控制

    • MVCC
      • 当前读与快照读
      • 三个隐式字段
      • Undo log与undo log版本链
        • undo log
        • 版本链
      • Readview

MVCC

MVCC 称 Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段undolog日志readView

当前读与快照读

当前读读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

快照读:简单的select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。

  • Read Committed:每次select,都生成一个快照读。
  • Repeatable Read:开启事务后第一个select语句才是快照读的地方。
  • Serializable:快照读会退化为当前读。

三个隐式字段

当我们创建一张表的时候,表中除了会又创建时添加的字段外,InnoDB还会自动的给我们添加三个隐藏字段及其含义分别是:

隐藏字段 含义
DB_TRX_ID 最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID。
DB_ROLL_PTR 回滚指针,指向这条记录的上一个版本,用于配合undolog,指向上一个版本。
DB_ROW_ID 隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。

上述的前两个字段是肯定会添加的,是否添加最后一个字段DB_ROW_ID,得看当前表有没有主键,如果有主键,则不会添加该隐藏字段。

Undo log与undo log版本链

undo log

回滚日志,在insertupdatedelete的时候产生的便于数据回滚的日志。当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除。而updatedelete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。

版本链

有一张原始的数据表为

id age name DB_TRX_ID DB_ROLL_PTR
2 30 A30 1 null

其中:
DB_TRX_ID:代表最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID,是
自增的。
DB_ROLL_PTR:由于这条数据是才插入的,没有被更新过,所以该字段值为null。

有四个并发事务同时访问这张表:
数据库InnoDB-MVCC-多版本并发控制_第1张图片

当执行完事务1,2,3中的对同一个数据的更改操作后,undo log会形成undo log版本链,记录数据变更之前的样子;然后更新记录,并且记录本次操作的事务ID,回滚指针,回滚指针用来指定如果发生回滚,回滚到哪一个版本。

不同事务或相同事务对同一条记录进行修改,会导致该记录的undo log生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。

数据库InnoDB-MVCC-多版本并发控制_第2张图片

Readview

ReadView(读视图)是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。

ReadView中包含了四个核心字段:

字段 含义
m_ids 当前活跃的事务ID集合
min_trx_id 最小活跃事务ID
max_trx_id 预分配事务ID,当前最大事务ID+1(因为事务ID是自增的)
creator_trx_id ReadView创建者的事务ID

而在readview中就规定了版本链数据的访问规则:

trx_id代表当前undolog版本链对应事务ID。

条件 是否可以访问 说明
trx_id ==creator_trx_id 可以访问该版本 成立,说明数据是当前这个事务更改的。
trx_id < min_trx_id 可以访问该版本 成立,说明数据已经提交了。
trx_id > max_trx_id 不可以访问该版本 成立,说明该事务是在ReadView生成后才开启。
min_trx_id <= trx_id<= max_trx_id 如果trx_id不在m_ids中,是可以访问该版本的 成立,说明数据已经提交。

不同的隔离级别,生成ReadView的时机不同:

  • READ COMMITTED:在事务中每一次执行快照读时生成ReadView。
  • REPEATABLE READ:仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。

READ COMMITTED中,每执行一次select语句就会执行快照读生成ReadView,然后数据库就会根据所生成的ReadView以及ReadView的版本链访问规则,到undo log版本链中匹配数据,最终决定此次快照读返回的数据。

RR隔离级别下,仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。而RR是可重复读,在一个事务中,执行两次相同的select语句,查询到的结果是一样的。

MVCC与锁机制保证了数据库的隔离性。数据事务的其他性质及保证可以参考:
Mysql事务详解-[数据库的隔离级别、脏读、不可重复读、幻读以及ACID性质与redo log与undo log]

你可能感兴趣的:(MySql,数据库,java,mysql)