文章目录
一、数据库的并发场景
有三种,分别是:
1、读-读:不存在任何问题,也不需要并发控制
2、读-写:有线程安全问题,可能会造成事务隔离问题,可能遇到脏读、幻读、不可重复读
3、写-写:有线程安全问题,可能会存在更新丢失问题,比如第一类更新丢失,第二类更新丢失
多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。
二、什么是MVCC?
MVCC(Multi-Version Concurrency Control,多版本并发控制),它是一种并发控制方法,用于在数据库管理系统中实现对数据库的并发访问。
Mysql的大多数事务性存储引擎使用的都不是简单的行级锁机制。他们会将行级锁和可以提高并发性能的多版本并发控制技术结合使用。不仅是Mysql,包括Oracle、PostreSQL以及其他一些数据库系统也都使用了MVCC,但各自的实现机制不尽相同,因为MVCC如何工作没有统一一个标准。
可以认为MVCC是行级锁的一个变种,但他在很多情况下避免了加锁操作,因此开销更低。根据其实现方式,不仅实现了非阻塞的读操作,写操作也只锁定必要的行。
MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。
2.1 当前读和快照读
当前读
每次读取的都是最新数据,但读的时候不允许写,写的时候不允许读。
通过锁机制来保证读取的数据无法通过其他事务进行修改UPDATE、DELETE、INSERT、SELECT … LOCK IN SHARE MODE、SELECT … FOR UPDATE都是当前读。
快照读
读写不冲突,在事务开始时确定需要读取的数据版本,接下来的读取都会使用这个版本的数据,不受其他事务影响。
当前读通常用于可重复读和串行化隔离级别,而快照读通常用于读已提交和可重复读隔离级别。
三、MVCC实现原理
在Mysql中,MVCC实现原理主要依赖三个部分:数据库隐式字段、undo log、Read View。
3.1 隐式字段
有三个,分别是DB_ROW_ID DB_TRX_ID DB_ROLL_PTR
详细解释参考以下文章:
数据库技术之MVCC的实现原理 之 隐式字段
3.2 undo log
undo log是一种用于撤销回退的日志,在事务没提交之前,mysql 会先记录更新前的数据到 undo log 日志里面,当事务回滚或者数据库更新崩溃时,使用undo log 进行回退。
在mysql中,undo log有两个作用:
1、提供回滚操作【undo log实现事务的原子性】
2、实现多版本并发控制
更多关于undo log的知识见此:
MySQL回滚日志(undo log)总结
3.3 ReadView
用来做可见性判断,它是事务进行快照读操作的时候生产的读视图(ReadView),它记录并维护系统当前活跃事务的ID。
Read View创建时包含四个部分,如图:
creator_trx_id:创建这个Read View的事务id
m_ids:表示创建ReadView时当前系统中的活跃事务的ID集合
(活跃指:启动了但未提交)
min_trx_id:表示创建ReadView时当前系统中的活跃的最小事务ID
max_trx_id:表示创建ReadView时系统中应该分配给下一个事务的id值,当前最大事务ID+1
可见性匹配原则
一个事务去访问记录的时候,怎么判断记录的可见性呢?
判断数据记录可见性的逻辑是通过readview和【行记录的隐藏字段trx_id】做对比的
Read View决定当前事务能读到哪个版本的数据,从表记录到Undo Log历史数据的版本链,依次匹配,满足哪个版本的匹配规则,就能读到哪个版本的数据,一旦匹配成功就不再往下匹配。
遵循了以下可见性匹配规则:
MVCC隔离级别分析
在不同的隔离级别下快照读生成的ReadView规则不同,区别如下:
read committed (读已提交):事务每次select时创建ReadView,每个ReadView中四个字段的值都是不同的
repeatable read (可重复读):事务第一次select时创建ReadView,后面都是复用这个ReadView
流程举例说明,文章后半段:
结合图文一起搞懂MySQL事务、MVCC、ReadView!
参考文章
亮点:有结合github仓库中的源码讲解:
一文读懂MySQL的事务隔离级别及MVCC机制