InnoDB实现4种事务的隔离级别

事务ACID特性,其中I表明隔离性(Isolation)。数据库

什么是事务的隔离性?

隔离性是指,多个用户的并发事务访问同一个数据库时,一个用户的事务不该该被其余用户的事务干扰,多个并发事务之间要相互隔离。并发

一个事务怎么会干扰其余事务呢?

我们举例子来讲明,假设有InnoDB表:高并发

t(id PK, name);大数据

 

表中有三条记录:spa

1, shenjian3d

2, zhangsanorm

3, lisi索引

 

case 1事务

事务A,先执行,处于未提交的状态:get

insert into t values(4, wangwu);

 

事务B,后执行,也未提交:

select * from t;

 

若是事务B可以读取到(4, wangwu)这条记录,事务A就对事务B产生了影响,这个影响叫作“读脏”,读到了未提交事务操做的记录。

 

case 2

事务A,先执行:

select * from t where id=1;

 

结果集为:

1, shenjian

 

事务B,后执行,而且提交:

update t set name=xxoo where id=1;

commit;

 

事务A,再次执行相同的查询:

select * from t where id=1;

 

结果集为:

1, xxoo

 

此次是已提交事务B对事务A产生的影响,这个影响叫作“不可重复读”,一个事务内相同的查询,获得了不一样的结果。

 

case 3

事务A,先执行:

select * from t where id>3;

 

结果集为:

NULL

 

事务B,后执行,而且提交:

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产生的影响,这个影响叫作“幻读”。

 

能够看到,并发的事务可能致使其余事务:

  • 读脏

  • 不可重复读

  • 幻读

 

InnoDB实现了哪几种事务的隔离级别?

按照SQL92标准,InnoDB实现了四种不一样事务的隔离级别:

  • 读未提交(Read Uncommitted)

  • 读提交(Read Committed, RC)

  • 可重复读(Repeated Read, RR)

  • 串行化(Serializable)

 

不一样事务的隔离级别,其实是一致性与并发性的一个权衡与折衷

 

InnoDB的四种事务的隔离级别,分别是怎么实现的?

InnoDB使用不一样的锁策略(Locking Strategy)来实现不一样的隔离级别。

 

一,读未提交(Read Uncommitted)

这种事务隔离级别下,select语句不加锁。

画外音:官方的说法是

SELECT statements are performed in a nonlocking fashion.

 

此时,可能读取到不一致的数据,即“读脏”。这是并发最高,一致性最差的隔离级别。

 

二,串行化(Serializable)

这种事务的隔离级别下,全部select语句都会被隐式的转化为select ... in share mode.

 

这可能致使,若是有未提交的事务正在修改某些行,全部读取这些行的select都会被阻塞住。

画外音:官方的说法是

To force a plain SELECT to block if other transactions have modified the selected rows.

 

这是一致性最好的,但并发性最差的隔离级别。

 

在互联网大数据量,高并发量的场景下,几乎不会使用上述两种隔离级别

 

三,可重复读(Repeated Read, RR)

这是InnoDB默认的隔离级别,在RR下:

 

(1)普通的select使用快照读(snapshot read),这是一种不加锁的一致性读(Consistent Nonlocking Read),底层使用MVCC来实现,具体的原理在《InnoDB并发如此高,缘由居然在这?》中有详细的描述;

 

(2)加锁的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)

这是互联网最经常使用的隔离级别,在RC下:

(1)普通读是快照读;

(2)加锁的select, update, delete等语句,除了在外键约束检查(foreign-key constraint checking)以及重复键检查(duplicate-key checking)时会封锁区间,其余时刻都只使用记录锁;

 

此时,其余事务的插入依然能够执行,就可能致使,读取到幻影记录。

 

总结

  • 并发事务之间相互干扰,可能致使事务出现读脏,不可重复度,幻读等问题

  • InnoDB实现了SQL92标准中的四种隔离级别

(1)读未提交:select不加锁,可能出现读脏;

(2)读提交(RC):普通select快照读,锁select /update /delete 会使用记录锁,可能出现不可重复读;

(3)可重复读(RR):普通select快照读,锁select /update /delete 根据查询条件状况,会选择记录锁,或者间隙锁/临键锁,以防止读取到幻影记录;

(4)串行化:select隐式转化为select ... in share mode,会被update与delete互斥;

  • InnoDB默认的隔离级别是RR,用得最多的隔离级别是RC

相关文章
相关标签/搜索