READ UNCOMMITTED(未提交读)
事务中的修改,即使没有提交,对其他事务也都是可见的,即读取了一个未提交的修改(脏读)
READ COMMITTED(提交读)
大多数数据库的默认隔离级别(mysql不是),满足ACID中的隔离性定义:一个事务开始时,只能看见已经提交的事务所做的修改。有点不能理解,在网上看到了一个例子:
singo拿着工资卡去消费,系统读取到卡里确实有2000元,而此时她的老婆也正好在网上转账,把singo工资卡的2000元转到另一账户,并在 singo之前提交了事务,当singo扣款时,系统检查到singo的工资卡已经没有钱,扣款失败,singo十分纳闷,明明卡里有钱,为 何……
出现上述情况,即我们所说的不可重复读 ,两个并发的事务,“事务A:singo消费”、“事务B:singo的老婆网上转账”,事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。
这里事务A两次读取到的数据都是已经提交的,不管是首次读取的2000,还是在B事务提交之后读取到的0,所以这个级别有时候也叫不可重复读。
当隔离级别设置为Read committed 时,避免了脏读,但是可能会造成不可重复读。
REPEATABLE READ(可重复度, mysql默认级别)
该级别保证同一个事务多次读取的结果是一致的,在同一个事务里,SELECT的结果是事务开始时时间点的状态,因此,同样的SELECT操作读到的结果会是一致的。用上面的例子说就是当singo拿着工资卡去消费时,一旦系统开始读取工资卡信息(即事务开始),singo的老婆就不可能对该记录进行修改,也就是singo的老婆不能在此时转账。但是这个级别会产生幻读,所谓幻读,指的是当某个事务在读取某个范围内的记录时,另一个事务又在该范围内插入新纪录,当前事务再次读取该范围的记录时会产生幻行。
幻读和不可重复读的区别
幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象
发生了幻觉一样。
不可重复读强调的是对同一个数据的修改得到两个不同的结果,幻读强调的是对结果集的插入或删除操作,产生了新的结果集。
Serializable (序列化)
Serializable 是最高的事务隔离级别,强制事务串行执行,简单来说就是读取的每一行数据都加锁,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻像读。
间隙锁(Next-Key锁)
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁),另外一方面,是为了满足其恢复和复制的需要。
举例来说,假如emp表中只有101条记录,其empid的值分别是 1,2,…,100,101,下面的SQL:
Select * from emp where empid > 100 for update;
是一个范围条件的检索,InnoDB不仅会对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录并不存在)的“间隙”加锁。
InnoDB使用间隙锁的目的,一方面是为了防止幻读,以满足相关隔离级别的要求,
√: 可能出现 ×: 不会出现
隔离级别 | 脏读 | 不可重复读 | 幻读 | 加锁读 |
---|---|---|---|---|
Read uncommitted | √ | √ | √ | × |
Read committed | × | √ | √ | × |
Repeatable read | × | × | √ | × |
Serializable | × | × | × | √ |
最后提一句
InnoDB采用两阶段锁协议,只有在commit和rollback的时候才会释放锁并且是同一时间释放,并且这里说的锁都是隐式加锁,InnoDB会根据隔离级别在需要的时候自动加锁。