乐趣区

mysqlMVCC

MVCC:多版本并发控制,不加锁就让多个事务并发读写,提高并发的读写性能

当前读 && 快照读??

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

    像 select …..lock in share mode (共享锁),

    select ….. for update (排他锁) ; 

    update, insert ,delete (排他锁)

    这些操作都是一种当前读。当前读实际上是一种加锁的操作,是悲观锁的实现。

  • 快照读:快照读的实现是基于多版本并发控制,既然是基于多版本,即 快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本 。快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;
    像不加锁的 select * from 操作就是快照读,即不加锁的非阻塞读,不涉及其他锁之间的冲突;

事务 ID

当每个事务开启时,都会被分配一个 ID, 这个 ID 是递增的,所以最新的事务,ID 值越大


MVCC 模型在 MySQL 中的具体实现原理:

1. 是由  3 个隐式字段,undo 日志,Read View 等去完成的

2. 旧数据存储在 UNDO 中,再通过 DB_ROLL_PTR 回溯查找历史版本

3. 通过 read view 判断行记录是否可见

隐藏字段

每行记录除了我们自定义的字段外,还有数据库隐式定义的字段

                    DB_TRX_ID

                   6byte,事务 ID:记录创建这条记录 / 最后一次修改该记录的事务 ID

                    DB_ROLL_PTR

                    7byte,回滚指针,指向这条记录的上一个版本

                    DB_ROW_ID

                    6byte,隐含的自增 ID(隐藏主键),如果数据表没有主键,InnoDB 会自动以 DB_ROW_ID 产生一个聚簇索引

例如下图:


(新 insert 记录的 DB_ROLL_PTR 指针为 NULL。修改新值后,记录的 DB_ROLL_PTR 回滚指针指向原始值在 Undo Log 日志的位置)

以一条 SQL 为例子:

事务隔离级别的区别:read view(一致性视图)

§ RR 隔离级别下,在每个事务开始的时候,会将当前系统中的所有的活跃事务拷贝到一个列表中(read view)。

§ RC 隔离级别下,在事务中的每个语句开始(select)时,会将当前系统中的所有的活跃事务拷贝到一个列表中(read view)

然后按照以下逻辑判断事务的可见性

如果上面的还是没有看懂,可以参看下面的逻辑图:

如果查询出来的结果是,数据不可见,那么就需要去 undo log 中查找最新的已提交的数据,通过 undolog 中记录的事务 id 和 read view 做比较,不在 readview 且最大的事务 id 就是满足条件的数据了。
!


总结:
说白了 MVCC 就是为了实现 读 (select)- 写冲突 不加锁,而这个读指的就是快照读。读 (select) 操作时不用阻塞写操作,写操作也不用阻塞读操作。

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

退出移动版