一、MVCC - 多版本并发控制
MySQL中的隔离级别不单单是通过加锁实现的,实际上读已提交和可重复读两种隔离级别,在实现上还需要一个辅助,这个辅助就是MVCC(多版本并发控制)。最早的数据库系统,只有读读之间可以并发,读写,写读,写写都要阻塞,引入多版本之后,只有写写之间相互阻塞,其他三种操作都可以并行,这样大幅度提高了InnoDB的并发度。
InnoDB是在undolog中实现的,通过undolog可以找回数据的历史版本。找回的数据历史版本可以提供给用户读(按照隔离级别的定义,有些读请求只能看到比较老的数据版本),也可以在回滚的时候覆盖数据页上的数据。在InnoDB内部中,会记录一个全局的活跃读写事务数组,其主要用来判断事务的可见性。
1.2 MVCC实现原理
InnoDB内部使用了MVCC机制,实现了一致性非阻塞读,大大提高了并发读写效率,写不影响读,且读到的是记录的镜像版本。
InnoDB的MVCC,是通过在每行记录的后面保存三个隐藏的列来实现的:
- 字节的事务ID(DB_TRX_ID):一个6byte的标识,每处理一个事务,其值自动+1,可以通过语句“show engine innodb status”来查找
- 字节的回滚指针(DB_ROLL_PTR):大小是7byte,指向写到rollback segment(回滚段)的一条undo log记录 (update操作的话,记录update前的ROW值)
- 行标识(DB_ROW_ID)
mvcc实现的依赖项:
- undo log:undo log中记录的是数据表记录行的多个版本,也就是事务记录过程中的回滚段,其实就是MVCC中的一行原始数据的多个版本镜像数据。
- redo log:主要用来判断当前版本数据的可见性。
undo log
undo log是为回滚而生,具体内容就是copy事务前的数据库内容(行)到undo buffer,在适合的时间把undo buffer 中的内容刷新到磁盘。undo buffer 与 redo buffer 一样,也是环形缓冲,但当缓存慢的适合,undo buffer中的内容也会被刷新到磁盘;与redo log 不同的是,磁盘上存在单独的undo log 文件,所有的undo log 均存放在idb数据文件中(表空间),即使客户端设置了每张表一个数据文件也是如此。
当事务更改行的值时,会进行如下操作:
- 用排他锁X锁锁定改行(实际是锁索引);
- 记录redo log;
- 把改行前的值copy到undo log;
- 修改当前行的值,填写事务编号,使回滚指针执行undo log中的修改前的行;