MySQL的实现:MySQL默认采用RR隔离级别,SQL标准是要求RR解决不可重复读的问题,但是因为MySQL采用了gap lock,所以实际上MySQL的RR隔离级别也解决了幻读的问题。那么MySQL的SERIALIZABLE是怎么回事呢?其实MySQL的SERIALIZABLE采用了经典的实现方式,对读和写都加锁。
5. MySQL 中RC和RR隔离级别的区别
MySQL数据库中默认隔离级别为RR,但是实际情况是使用RC 和 RR隔离级别的都不少。好像淘宝、网易都是使用的 RC 隔离级别。那么在MySQL中 RC 和 RR有什么区别呢?我们该如何选择呢?为什么MySQL将RR作为默认的隔离级别呢?
5.1 RC 与 RR 在锁方面的区别
1> 显然 RR 支持 gap lock(next-key lock),而RC则没有gap lock。因为MySQL的RR需要gap lock来解决幻读问题。而RC隔离级别则是允许存在不可重复读和幻读的。所以RC的并发一般要好于RR;
2> RC 隔离级别,通过 where 条件过滤之后,不符合条件的记录上的行锁,会释放掉(虽然这里破坏了“两阶段加锁原则”);但是RR隔离级别,即使不符合where条件的记录,也不会是否行锁和gap lock;所以从锁方面来看,RC的并发应该要好于RR;另外 insert into t select ... from s where 语句在s表上的锁也是不一样的,参见下面的例子2;
例子1:
MySQL5.6, 隔离级别RR,autocommit=off;
表结构:
mysql> show create table t1\G *************************** 1. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `a` int(11) NOT NULL, `b` int(11) NOT NULL, `c` int(11) NOT NULL, `d` int(11) NOT NULL, `e` varchar(20) DEFAULT NULL, PRIMARY KEY (`a`), KEY `idx_t1_bcd` (`b`,`c`,`d`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 1 row in set (0.00 sec)
表数据:
mysql> select * from t1; +---+---+---+---+------+ | a | b | c | d | e | +---+---+---+---+------+ | 1 | 1 | 1 | 1 | a | | 2 | 2 | 2 | 2 | b | | 3 | 3 | 2 | 2 | c | | 4 | 3 | 1 | 1 | d | | 5 | 2 | 3 | 5 | e | | 6 | 6 | 4 | 4 | f | | 7 | 4 | 5 | 5 | g | | 8 | 8 | 8 | 8 | h | +---+---+---+---+------+ 8 rows in set (0.00 sec)
操作过程:
session 1:
delete from t1 where b>2 and b<5 and c=2;
执行计划如下:
mysql> explain select * from t1 where b>2 and b<5 and c=2\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t1 type: range possible_keys: idx_t1_bcd key: idx_t1_bcd key_len: 4 ref: NULL rows: 2 Extra: Using index condition 1 row in set (0.00 sec)
session 2:
delete from t1 where a=4
结果 session 2 被锁住。
session 3: