InnoDB可重复读隔离级别下如何避免幻读
- 表象:快照读(非阻塞读)–伪MVCC
- 内在:next-key锁(行锁 + gap锁)
当前读和快照读
- 当前读:select…lock in share mode,select…for update
- 当前读:update,delete,insert
就是加了锁的增删改查语句,不管你上的是共享锁还是排他锁均为当前读,那为什么叫做当前读呢,因为它读取的是记录的最新版本,读取之后还要保证其他并发不能修改当前记录,对读取的记录加锁,其中除了第一条语句加了共享锁之外,其他都会加上排他锁。那为什么update、delete、insert也是当前读呢?我们了解到rdbs有两大实例。
- 快照读:不加锁的非阻塞读,select
有快照读是因为想提升并发效率的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行级锁的一种变种,但是它在很多情况下避免了加锁操作,开销更低是基于多版本,也就以为着快照读有可能读到的并不是数据的最新版本,可能是之前的历史版本,咱们来看看实际的例子
开启4个session,其中两个是RC,两个是RR
session1
select @@tx_isolation; //事务隔离级别为 READ-COMMITTED
start transaction;
SELECT * FROM account_innodb where id = 2;
select * from account_innodb where id = 2 lock in share mode;
session2
select @@tx_isolation; //事务隔离级别为 READ-COMMITTED
update account_innodb set balance = 600 where id = 2;
commit;
session1
start transaction;
select @@tx_isolation; //事务隔离级别为 REPEATABLE-READ
select * from account_innodb where id = 2;
select * from account_innodb where id = 2 lock in share mode;
快照读
返回的是没更新前的版本
当前读
session2
select @@tx_isolation; //事务隔离级别为 REPEATABLE-READ
update account_innodb set balance = 0 where id = 2;
commit;
RC、RR级别下的InnoDB的非阻塞读如何实现
- 数据行里的DB_TRX_ID(表示最后一个事务的更新和插入)、DB_ROLL_PTR(指向当前记录项的undo log信息)、DB_ROW_ID(标识插入的新的数据行的id)字段
- undo日志(insert update)
- read view(来判断数据是否是最新版,还是旧版)
RC(读已提交)和RR(可重复度)