MVCC
MVCC就是多版本并发控制,主要处理读请求,而且是快照读
- 快照读: 就是select查询
- 当前读: 读取的数据都是最新版本的,会对读取的数据进行加锁,属于悲观锁的一种操作
MVCC是基于undo log加版本链 和 read view去实现的
- undo log日志: 它记录的是对数据库的操作,除了会保存每次操作的数据,还会有trx_id和roll_pointer字段,trx_id就是事务id,是自增的,roll_pointer是指向上一个版本的回滚指针
- 版本链: 由undo log日志中的每一天记录通过roll_pointer链接而成的一个链表
- read view: 是一个快照,其实就是一个对象,用来判断该使用版本链中的哪个版本,有以下属性
- m_ids: 在生成read view时活跃的事务id,即未提交的事务的id
- min_trx_id: 在生成read view时最小的活跃的事务id,即m_ids中最小的那个
- max_trx_id: 在生成read view时,系统应该分配给下一个事务的id
- creator_trx_id: 表示生成该read view的事务的事务id
- 判断规则:
- trx_id == creator_trx_id: 可以访问该版本,表示该条记录是自己创建的
- trx_id < min_trx_id: 可以访问,表示小于最小的活跃事务id,即该trx_id所对应的事务一定是提交了的
- trx_id > max_trx_id: 不可以访问,表示该事务id大于系统即将分配的事务id,一定是没有提交的事务
- min_trx_id <= trx_id <= max_trx_id: 如果trx_id在m_ids中,就不可以访问,不在就行,因为m_ids中的id并不一定是连续的,所以可能或出现已经提交的事务,已提交的事务是可以访问的
MVCC是如何实现不可重复读和可重复读?
其实就是创建read view的时机不同
- 不可重复读: 每次select,即快照读都会生成一份read view,这样,每次都能读到新的已提交的事务,就实现了不可重复读
- 可重复读: read view在整个事务期间只会生成一份,这样就不能读取到新提交的事务,就实现了可重复读
值得一提的是,innoDB引擎下,可以通过间隙锁解决幻读问题的,而且innoDB引擎是默认开启间隙锁的