当前读、快照读、MVCC
当前读
- 当前读, 读取的是最新版本, 并且对读取的记录加锁, 阻塞其他事务同时改动相同记录,避免出现安全问题。
- 操作:
- select…lock in share mode (共享读锁)
- select…for update
- update , delete , insert
- 实现方式:行锁+间隙锁
- 加锁
- 对主键或唯一索引,如果当前读时,where条件全部精确命中(=或者in),这种场景本身就不会出现幻读,所以只会加行记录锁。
- 没有索引的列,当前读操作时,会加全表gap锁,生产环境要注意。
- 非唯一索引列,如果where条件部分命中(>、<、like等)或者全未命中,则会加附近Gap间隙锁。例如,某表数据如下,非唯一索引2,6,9,9,11,15。如下语句要操作非唯一索引列9的数据,gap锁将会锁定的列是(6,11],该区间内无法插入数据。
快照读
- 读取快照数据,也就是说当某个数据正在被修改的时候,也可以进行读取该数据,保证读写不冲突。
- 实现方式: undolog和多版本并发控制(MVCC)
如何实现快照读
- 快照”不是全量拷贝,而是利用了数据多版本的特性,也就是MVCC
- MVCC的核心在于每个事务自己维护的一个事务ID数组
- 只有“快照读”的sql语句,才会生成快照,比如不加锁的select语句;
- 而“当前读”的sql语句,是不会生成快照的,比如update,select … for update, select .. lock in share mode等;
- Read Committed隔离级别:每次select都生成一个快照读。
- Read Repeatable隔离级别:开启事务后第一个select语句才是快照读的地方,而不是一开启事务就快照读。
- 可见性的原则
- 版本未提交,不可见;
- 版本已提交,但是是在快照创建后提交的,不可见;
- 版本已提交,而且是在快照创建前提交的,可见。