MySQL使用可重复读作为默认隔离级别的原因(3)

因此,在RR中,以上测试会话1、会话2的依次执行,与Binlog的顺序一致,从而保证DB/DR一致。

幻象读

除了保证可重复读,MySQLRR还一定程度上避免了幻象读(幻象读是由于插入导致的新记录)。(为什么说一定程度呢?参考第3节可重复读和串行化的区别。)

会话1

 

会话2

 

use test;

#初始化数据

create table t1(c1 int primary key, c2 int) engine=innodb;

create table t2(c1 int primary key, c2 int) engine=innodb;

insert into t1 values(1,1), (10,10);

insert into t2 values(1,1), (5,5), (10,10);

#设置隔离级别

set tx_isolation='repeatable-read';

Query OK, 0 rows affected (0.00 sec)

#连续更新两次

mysql> Begin;

Query OK, 0 rows affected (0.03 sec)

mysql> update t2 set c2 = 20 where c1 in (select c1 from t1);

Query OK, 2 rows affected (0.00 sec)

Rows matched: 2  Changed: 2  Warnings: 0

mysql> delete from where c1 in (select c1 from t1);

Query OK, 2 rows affected (0.00 sec)

Rows matched: 2  Changed: 2  Warnings: 0

mysql> select * from t2;

+------+------+

| c1   | c2   |

+------+------+

|    5 |    5 |

+------+------+

2 rows in set (0.00 sec)

mysql> commit;

 

#设置隔离级别

set tx_isolation=' repeatable-read';

Query OK, 0 rows affected (0.00 sec)

#两次更新之间执行插入

mysql> insert into t1 values(5,5);

--阻塞,直到会话1提交

Query OK, 1 row affected (18.94 sec)

 

由上述例子知,会话2的插入操作被阻塞了,原因是RR隔离级别中,除了记录锁外,还会上间隙锁(gap)。例如,对于表t1update t2 set c2 = 20 where c1 in (select c1 from t1)以上的锁包括:

(-∞, 1), 1, (1, 10), 10, (10, +∞)

由于对t1做全表扫描,因此,所有记录和间隙都要上锁,其中(x,y)表示间隙锁,数字表示记录锁,全部都是S锁。会话2insert操作插入5,位于间隙(1,10),需要获得这个间隙的X锁,因此两操作互斥,会话2阻塞。

SQL标准的RR并不要求避免幻象读,而InnoDB通过gap锁来避免幻象,���而实现SQL的可串行化,保证Binlog的一致性。

要想取消gap lock,可使用参数innodb_lock_unsafe_for_binlog=1,默认为0

3. 可重复读与串行化的区别

InnoDBRR可以避免不可重复读和幻象读,那么与串行化有什么区别呢?

会话1

 

会话2

 

use test;

#初始化数据

create table t3(c1 int primary key, c2 int) engine=innodb;

#设置隔离级别

set tx_isolation='repeatable-read';

Query OK, 0 rows affected (0.00 sec)

mysql> Begin;

Query OK, 0 rows affected (0.03 sec)

mysql> select * from t3 where c1 = 1;

Empty set (0.00 sec)

mysql> select * from t3 where c1 = 1;

Empty set (0.00 sec)

mysql> update t3 set c2 =2 where c1 = 1;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from t3 where c1 = 1;

+----+------+

| c1 | c2   |

+----+------+

|  1 |    2 |

+----+------+

1 row in set (0.00 sec)

mysql> commit;

 

#设置隔离级别

set tx_isolation=' repeatable-read';

Query OK, 0 rows affected (0.00 sec)

mysql> insert into t3 values(1,1);

Query OK, 1 row affected (0.05 sec)

 

由上述会话1中,连续两次读不到数据,但更新却成功,并且更新后的相同读操作就能读到数据了,这算不算幻读呢?

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

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