mysql之semi-consistent read知悉

时间:2025-03-19 11:36:00

semi-consistent read是什么

简单来说,semi-consistent read是read committed与consistent read两者的结合。一个update语句(semi-consistent read只针对update),如果读到一行已经加锁的记录,此时InnoDB返回记录最近提交的版本,由MySQL上层判断此版本是否满足update的where条件。若满足(需要更新),则MySQL会重新发起一次读操作,此时会读取行的最新版本(并加锁)。
(对于update scan返回的不满足条件的记录,会提前放锁)

使用限制

1、semi-consistent read只会发生在read committed隔离级别下
2、或者是参数innodb_locks_unsafe_for_binlog被设置为true。

优缺点

优点
1、减少了更新同一行记录时的冲突,减少锁等待。无并发冲突,读记录最新版本并加锁;有并发冲突,读事务最新的commit版本,不加锁,无需锁等待。
2、可以提前放锁,进一步减少并发冲突概率。对于不满足update更新条件的记录,可以提前放锁,减少并发冲突的概率。
3、在理解了semi-consistent read原理及实现方案的基础上,可以酌情考虑使用semi-consistent read,提高系统的并发性能。
缺点
1、非冲突串行化策略,因此对于binlog来说,是不安全的

为什么对于binlog来说是不安全的

这里又要提到上面所说的使用限制:RC级别下或者innodb_locks_unsafe_for_binlog为true。
如果innodb_locks_unsafe_for_binlog=true,就相当于禁止了gap锁。
粗略的可以理解为从RR降为RC隔离级别,毕竟RR与RC最大的不同在于gap锁(防止幻读)。

那就会出现以下问题:

session 1:
begin;
delete from a where b<=5;

session 2:
begin;
insert into a select 3;
commit;

session 1:
commit;

主库:
select * from a;

b
3

从库:
select * from a;
empty set

分析如下:

因为rc下没有gap锁,所以在session1把b<=5的记录加上X锁时,session2加了一条3的记录,而3没有被加锁也没有被选中,然后session2提交后,session1把3插入之前就选中的数据删除,所以主库有一条记录,而从库是根据binlog做数据同步的,binlog为statement记录的是master上产生的sql语句,按提交顺序记录的,因此binlog中记录的是先插入数据,后删除数据,所以产生了数据的不一致,因此semi-consistent read不建议使用。