【mysql】MVCC

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产生一个聚簇索引

例如下图:

【mysql】MVCC_第1张图片
(新insert记录的DB_ROLL_PTR指针为NULL。修改新值后,记录的 DB_ROLL_PTR 回滚指针指向原始值在Undo Log 日志的位置)

以一条SQL为例子:
【mysql】MVCC_第2张图片

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

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

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

然后按照以下逻辑判断事务的可见性
【mysql】MVCC_第3张图片

如果上面的还是没有看懂,可以参看下面的逻辑图:
【mysql】MVCC_第4张图片

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


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

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

你可能感兴趣的:(mysql)