事务ACID特性,其中I代表隔离性(Isolation)。
隔离性是指,多个用户的并发事务访问同一个数据库时,一个用户的事务不应该被其他用户的事务干扰,多个并发事务之间要相互隔离。
t(id PK, name);
1, shenjian
2, zhangsan
3, lisi
insert into t values(4, wangwu);
select * from t;
如果事务B能够读取到(4, wangwu)这条记录,事务A就对事务B产生了影响,这个影响叫做“读脏”,读到了未提交事务操作的记录。
select * from t where id=1;
1, shenjian
update t set name=xxoo where id=1;
commit;
select * from t where id=1;
1, xxoo
这次是已提交事务B对事务A产生的影响,这个影响叫做“不可重复读”,一个事务内相同的查询,得到了不同的结果。
select * from t where id>3;
NULL
insert into t values(4, wangwu);
commit;
事务A,首次查询了id>3的结果为NULL,于是想插入一条为4的记录:
insert into t values(4, xxoo);
Error : duplicate key!
事务A的内心OS是:你TM在逗我,查了id>3为空集,insert id=4告诉我PK冲突?
这次是已提交事务B对事务A产生的影响,这个影响叫做“幻读”。
按照SQL92标准,InnoDB实现了四种不同事务的隔离级别:
(1)读未提交(Read Uncommitted);
(2)读提交(Read Committed, RC);
(3)可重复读(Repeated Read, RR);
不同事务的隔离级别,实际上是一致性与并发性的一个权衡与折衷。
InnoDB的四种事务的隔离级别,分别是怎么实现的?
InnoDB使用不同的锁策略(Locking Strategy)来实现不同的隔离级别。
SELECT statements are performed in a nonlocking fashion.
此时,可能读取到不一致的数据,即“读脏”。这是并发最高,一致性最差的隔离级别。
这种事务的隔离级别下,所有select语句都会被隐式的转化为select ... in share mode.
这可能导致,如果有未提交的事务正在修改某些行,所有读取这些行的select都会被阻塞住。
To force a plain SELECT to block if other transactions have modified the selected rows.
三,可重复读(Repeated Read, RR)
(1)普通的select使用快照读(snapshot read),这是一种不加锁的一致性读(Consistent Nonlocking Read),底层使用MVCC来实现,具体的原理在《InnoDB并发如此高,原因竟然在这?》中有详细的描述;
(3)加锁的select(select ... in share mode / select ... for update), update, delete等语句,它们的锁,依赖于它们是否在唯一索引(unique index)上使用了唯一的查询条件(unique search
condition),或者范围查询条件(range-type search condition):
- 在唯一索引上使用唯一的查询条件,会使用记录锁(record lock),而不会封锁记录之间的间隔,即不会使用间隙锁(gap lock)与临键锁(next-key lock)
- 范围查询条件,会使用间隙锁与临键锁,锁住索引记录之间的范围,避免范围间插入记录,以避免产生幻影行记录,尽量避免不可重复的读
四,读提交(Read Committed, RC)
(2)加锁的select, update, delete等语句,除了在外键约束检查(foreign-key constraint checking)以及重复键检查(duplicate-key checking)时会封锁区间,其他时刻都只使用记录锁;
此时,其他事务的插入依然可以执行,就可能导致,读取到幻影记录。
(1)并发事务之间相互干扰,可能导致事务出现读脏,不可重复度,幻读等问题;
(2)InnoDB实现了SQL92标准中的四种隔离级别;
- 读提交(RC):普通select快照读,锁select /update /delete 会使用记录锁,可能出现不可重复读;
- 可重复读(RR):普通select快照读,锁select /update /delete 根据查询条件情况,会选择记录锁,或者间隙锁/临键锁,以防止读取到幻影记录;
- 串行化:select隐式转化为select ... in share mode,会被update与delete互斥;
(3)InnoDB默认的隔离级别是RR,用得最多的隔离级别是RC;
架构师之路-分享可落地的架构文章
画外音:本文内容基于MySQL5.6,为了避免误传,多处带入了MySQL官网英文。
发布者:糖太宗,转载请注明出处:https://www.qztxs.com/archives/science/technology/6631