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 不兼容。因为读未提交总是读取最新的数据行,而不是符合当前事务版本的数据行,而串行化则会对所有读取的行都加锁。