读偏序(Read Skew)
在已提交读(read committed)事务隔离级别下,事务T1先读取数据X,然后事务T2修改数据X和Y,然后事务T1再读取数据Y,事务T1读取到的X和Y不满足一致性约束。
在可重复读(Repeatable Read)事务隔离级别下,事务T1先读取数据X,然后事务T2修改数据X和Y,然后事务T1再读取数据Y,事务T1读取到的X和Y都是T2修改前的数据,满足一致性约束。
写偏序(Write Skew)
写偏序(Write Skew)也是一致性约束下的异常现象,即两个并行事务都基于自己读到的数据集去覆盖另一部分数据集,在串行化的情况下两个事务无论那种顺序执行,最终都会达到一致状态,但在快照(Snap)事务隔离级别下无法实现,即黑白球问题:
如下面场景:
## 初始化测试数据
CREATE TABLE tb1001(id INT PRIMARY KEY,c1 INT);
CREATE TABLE tb1002(id INT PRIMARY KEY,c1 INT);
INSERT INTO tb1001(id,c1)VALUES(1,11);
INSERT INTO tb1002(id,c1)VALUES(1,22);
在事务T1中执行:
BEGIN;
UPDATE tb1001 AS T1
INNER JOIN tb1002 AS T2
ON T1.id=T2.id
SET T1.c1=T2.c1;
在事务T2中执行:
BEGIN;
UPDATE tb1001 AS T1
INNER JOIN tb1002 AS T2
ON T1.id=T2.id
SET T2.c1=T1.c1;
在快照(Snap)事务隔离级别下,事务通过快照来读取数据,并不会对数据进行加锁保护,执行SQL不会被阻塞,由于两个事务修改的数据没有冲突,因此能够提交成功。
在MySQL的已提交读(read committed)事务隔离级别或可重复读(Repeatable Read)事务隔离级别时,MySQL会对更新的记录加X锁进行保护,对更新依赖的记录在读取时加S锁进行保护,因此当事务T1未提交前,事务T2被被阻塞,等待锁信息为:
mysql> select * from information_schema.INNODB_LOCKS \G
*************************** 1. row ***************************
lock_id: 11916729688:830:3:2
lock_trx_id: 11916729688
lock_mode: S
lock_type: RECORD
lock_table: `test`.`tb1001`
lock_index: PRIMARY
lock_space: 830
lock_page: 3
lock_rec: 2
lock_data: 1
*************************** 2. row ***************************
lock_id: 11916729687:830:3:2
lock_trx_id: 11916729687
lock_mode: X
lock_type: RECORD
lock_table: `test`.`tb1001`
lock_index: PRIMARY
lock_space: 830
lock_page: 3
lock_rec: 2
lock_data: 1
2 rows in set (0.00 sec)