MySQL 中隔离级别 RC 与 RR 的区别(4)

RC和RR隔离级别中的锁处理不一样,RC隔离级别时,在使用c列进行ICP where条件过滤时,对于不符合条件的记录,锁会释放掉,而RR隔离级别时,即使不符合条件的记录,锁也不会释放(虽然违反了“2阶段锁”原则)。所以RC隔离级别时session 2不会被阻塞。

Gap lock: This is a lock on a gap between index records, or a lock on the gap before the first or after the last index record.

例子2:insert into t select ... from s where 在RC 和 RR隔离级别下的加锁过程

下面是官方文档中的说明:

INSERT INTO T SELECT ... FROM S WHERE ... sets an exclusive index record lock (without a gap lock) on each row inserted into T. If the transaction isolation level is READ COMMITTED, or innodb_locks_unsafe_for_binlog is enabled and the transaction isolation level is not SERIALIZABLE, InnoDB does the search on S as a consistent read (no locks). Otherwise, InnoDB sets shared next-key locks on rows from S. InnoDB has to set locks in the latter case: In roll-forward recovery from a backup, every SQL statement must be executed in exactly the same way it was done originally.

CREATE TABLE ... SELECT ... performs the SELECT with shared next-key locks or as a consistent read, as for INSERT ... SELECT.

When a SELECT is used in the constructs REPLACE INTO t SELECT ... FROM s WHERE ... or UPDATE t ... WHERE col IN (SELECT ... FROM s ...), InnoDB sets shared next-key locks on rows from table s.

insert inot t select ... from s where ... 语句和 create table ... select ... from s where 加锁过程是相似的(RC 和 RR 加锁不一样)

1> RC 隔离级别时和 RR隔离级别但是设置innodb_locks_unsafe_for_binlog=1 时,select ... from s where 对 s 表进行的是一致性读,所以是无需加锁的;

2> 如果是RR隔离级别(默认innodb_locks_unsafe_for_binlog=0),或者是 serializable隔离级别,那么对 s 表上的每一行都要加上 shared next-key lock.

这个区别是一个很大的不同,下面是生成中的一个 insert into t select ... from s where 导致的系统宕机的案例:

一程序猿执行一个分表操作:

insert into tb_async_src_acct_201508 select * from tb_async_src_acct

where src_status=3 and create_time>='2015-08-01 00:00:00' and create_time <= '2015-08-31 23:59:59';

表 tb_async_src_acct有4000W数据。分表的目的是想提升下性能。结果一执行该语句,该条SQL被卡住,然后所有向 tb_async_src_acct的写操作,要么是 get lock fail, 要么是 lost connection,全部卡住,然后主库就宕机了

显然这里的原因,就是不知道默认RR隔离级别中 insert into t select ... from s where 语句的在 s 表上的加锁过程,该语句一执行,所有符合 where 条件的 s 表中的行记录都会加上 shared next-key lock(如果没有使用到索引,还会锁住表中所有行),在整个事务过程中一直持有,因为表 tb_async_src_acct 数据很多,所以运行过程是很长的,所以加锁过程也是很长,所以其它所有的对 tb_async_src_acct 的insert, delete, update, DDL 都会被阻塞掉,这样被阻塞的事务就越来越多,而事务也会申请其它的表中的行锁,结果就是系统中被卡住的事务越来越多,系统自然就宕机了。

5.2 RC 与 RR 在复制方面的区别

1> RC 隔离级别不支持 statement 格式的bin log,因为该格式的复制,会导致主从数据的不一致;只能使用 mixed 或者 row 格式的bin log; 这也是为什么MySQL默认使用RR隔离级别的原因。复制时,我们最好使用:binlog_format=row

具体参见:

2> MySQL5.6 的早期版本,RC隔离级别是可以设置成使用statement格式的bin log,后期版本则会直接报错;

5.3 RC 与 RR 在一致性读方面的区别

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/ca76e42465f55c8e0d16d71be54596cd.html