MySQL锁机制与MVCC原理剖析
在MySQL中,我们使用到了它的各种类锁;按照它的维度,有各种锁
- 从数据库的操作粒度有,表锁,行锁。
- 从数据库的操作的类型,有读锁和写锁。
- 性能上有乐观锁和悲观锁。
在上一篇文章中的事务隔离级别,需要解决的是不可重复读和幻读问题,所以在遍历扫描聚集索引记录时,为了防止扫描过的索引被其他事务修改,从而导致数据不一致。这里引用了间隙锁
间隙锁(Gap Lock)
锁的是这两个值直接的间隙,间隙锁的在可重复读隔离级别下才会生效。
MVCC(Multi-Version Concurrency Control)
隔离性就是靠MVCC机制来保证的,对一行数据的读和写两个操作默认是不会通过加锁互斥来保证隔离性,避免了频繁加锁互斥。
MySQL在可重复读和读已提交的隔离级别实现了MVCC机制。
undo日志版本链与read view机制
undo日志版本是指一行数据被多个事务依次修改后,每个事务修改完成后,MySQL会保留修改前的数据undo回滚日志,并用2个隐藏日志trx_id和roll_pointer把这些undo日志串联起来形成一个历史版本记录链。
在可重复读隔离级别,当事务开启,执行任何查询sql时会生成当前失误的一致性视图read-view,该视图在事务结束之前永远都不会变化;
这个视图由执行查询时所有未提交事务id数组(数组最小的id为min_id)和已创建的最大事务id(max_id)组成,事务里的任何sql查询结果需要从对应版本链里的最新数据逐条跟read_view做对比从而得到最终的快照结果。
版本链对比规则:
1.如果row的trx_id落在最小min_id部分(trx_id < min_id),表示这个版本是已提交的事务生成的,这个数据是可见的。
2.如果row的trx_id落在最大部分(trx_id > max_id),表示这个版本是将来期待的事务生成的,是不可见的。
3.如果row的trx_id落在了之间(min_id <= trx_id <= max_id),那么就有2种情况
a.若trx_id在视图数组中,标识这个版本是由还没提交的事务生成的,不可见。
b.若trx_id不在视图数组中,表示这个版本是已经提交了的事务生成的,可见。
事务隔离级别为 读已提交的,每次执行sql都会重新生成read-view,故不会出现上述问题。
RR级别中,select1的事务中,查询的结果为500,虽然事务100进行了更新数据,再次进行select1的事务时,由于属于上述版本中的版本链对比,commite结果也不可见,故而第二次查询的结果依旧为500.
而select 2开始查询的时候,由于已经commite,故而查询结果为1000.
如果是RC隔离级别的话,每次的read view会进行变化,两次查询会为 500和1000