数据库的隔离等级总结(重点区分sql标准中的不可重复读和幻读)
《高性能mysql》这本书中,在解释sql标准的隔离等级的时候,有一些含混,造成理解不清。主要的原因在于理解,幻读,脏读和不可重复读的区别。在书中,幻读,脏读和不可重复读是如下解释的
-
脏读(Dirty Read):事务可以读取未提交的数据,被称为脏读。
-
不可重复读(nonrepeatable read):两次执行相同的查询,可能会得到不一样的结果。
-
幻读(Phantom Read):当某个事物在读取某个范围的的记录的时候,另一个事务又在该范围内插入新的记录,当之前的事务再次读取该范围的记录的时候,会产生幻行(Phantom Row)。
我最开始的时候很迷惑,我在想幻读和不可重复读不是一个概念吗,都是连续两次读取得到的结果不一样。
事实上不可重复读是包含幻读的概念的。
幻读是你的查询语句是试图获取一个范围内的数据,注意是一个范围的数据,加入第一次的时候试图获取的范围包含a,b,c,第二次读取的时候其它事务添加了数据d,而d也满足你的查询范围,所以第二次查询的时候,会试图去获取a,b,c,d。这种情况就叫做幻读。
而不可重复读在幻读的基础上,还包含一种情况,就是当你读取指定行的数据,两次读取可能会不一样。举例说明:假如第一次你试图获取a,b,c,第二次依旧试图获取a,b,c。但是在第二次试图获取a,b,c的时候,可能会发生两种情况,第一个是b没有,被其它事务删除了,第二是c的内容被改变。
以上就是幻读和不可重复读的区别。
下面贴上sql标准对四种隔离等级的定义
-
Read Uncommited (未提交读):事务中的修改,即使没有提交,对其它事务也都是可见的,事务可以读取未提交的数据。
-
Read Committed(提交读):一个事务在提交之前,所做的任何修改对其它事务都是不可见的。但是当其它事务修改数据的时候,可能会造成两次读取的结果不一样。故提交读存在不可重复读的现状。
-
Repeatable Read(可重复读):该级别保证统一事务读取同样记录的结果一致。但是当出现读取一定范围的记录的时候,会因为其它事务在该事务提交之前插入数据,导致读取新插入的数据。产生幻读。
-
Serializable (可串行化):强制事务串行的执行,并发性能最低,但是避免了上述的问题。
额外说明:很多博客提出说repeatble read解决了幻读的问题,这是错误,实际上应该说mysql的InnoDB和部分引擎通过使用MVCC (Multiversion Concurrency Control 多版本并发控制)技术,实现了在提交读级别的解决幻读问题的方案。当然这个办法牺牲的是空间。
参考:
《高性能mysql》第三版,电子工业出版社,Baron Schwartz等著
你若盛开的博客-标准SQL规范中定义的四个事务隔离级别