不可重复读和幻像读有什么区别?

时间:2012-06-15 01:54:04

标签: database oracle transactions isolation-level transaction-isolation

非可重复读取和幻像读取之间有什么区别?

我已阅读Isolation (database systems) article from Wikipedia,但我有些疑惑。在下面的示例中,会发生什么:不可重复读取幻像读取

交易A
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1
输出:
1----MIKE------29019892---------5000
交易B
UPDATE USERS SET amount=amount+5000 where ID=1 AND accountno=29019892;
COMMIT;
交易A
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1

另一个疑问是,在上面的例子中,应该使用哪个隔离级别?为什么?

9 个答案:

答案 0 :(得分:130)

From Wikipedia(其中有很好的详细示例):

  

发生不可重复的读取,当在事务过程中,一行被检索两次,并且行内的值在读取之间不同。

  

当在事务过程中执行两个相同的查询,并且第二个查询返回的行集合与第一个查询不同时,会发生幻像读取。

简单示例:

  • 用户A运行相同的查询两次。
  • 在两者之间,用户B运行一个事务并提交。
  • 不可重复读取:用户A查询过的A行第二次具有不同的值。
  • 幻像读取:查询中的所有行在之前和之后具有相同的值,但是正在选择不同的行(因为B已删除或插入了一些)。示例:select sum(x) from table;将返回不同的结果,即使已添加或删除行,也不会更新任何受影响的行本身。
  

在上面的例子中,要使用哪个隔离级别?

您需要什么样的隔离级别取决于您的应用程序。 “更好”的隔离级别(例如降低的并发性)成本很高。

在您的示例中,您不会进行幻像读取,因为您只从一行(由主键标识)中选择。您可以进行不可重复的读取,因此如果这是一个问题,您可能希望具有阻止它的隔离级别。在Oracle中,事务A也可以发出SELECT FOR UPDATE,然后事务B在A完成之前不能更改行。

答案 1 :(得分:100)

我想考虑的一个简单方法是:

非可重复和幻像读取都与来自不同事务的数据修改操作有关,这些操作在您的事务开始后提交,然后由您的事务读取。

不可重复读取是指您的交易从另一个交易中读取提交更新的时间。现在,同一行的值与您的交易开始时的值不同。

幻像读取类似,但是从另一个事务中读取已提交的 INSERTS 和/或 DELETES 时。自您开始交易以来,新的行或行已经消失。

脏读取类似到非可重复和幻像读取,但与读取UNCOMMITTED数据有关,并且在读取来自另一个事务的UPDATE,INSERT或DELETE时发生,而另一个事务具有尚未提交数据。它正在读取“进行中”数据,这些数据可能不完整,可能永远不会被提交。

答案 2 :(得分:20)

this article中所述,不可重复读取异常如下所示:

enter image description here

  1. Alice和Bob开始两个数据库事务。
  2. 鲍勃(Bob)阅读帖子记录,标题栏的值为“交易”。
  3. Alice将给定帖子记录的标题修改为ACID的值。
  4. 爱丽丝进行她的数据库事务。
  5. 如果鲍勃(Bob)重新阅读了帖子记录,他将观察到该表行的另一种版本。

在关于{strong>幻影阅读的this article中,您可以看到这种异常可能发生如下:

enter image description here

  1. Alice和Bob开始两个数据库事务。
  2. Bob读取所有与标识符值为1的帖子行相关的post_comment记录。
  3. Alice添加了一个新的post_comment记录,该记录与标识符值为1的帖子行相关联。
  4. 爱丽丝进行她的数据库事务。
  5. 如果Bob重新读取post_id列的值等于1的post_comment记录,他将观察到该结果集的另一个版本。

因此,尽管不可重复读取适用于单行,但虚拟读取是关于满足给定查询过滤条件的一系列记录。

答案 3 :(得分:10)

Read phenomena

  • 脏读 :从其他交易中读取未经审核的数据
  • 不可重复的读取 :从另一个交易中的UPDATE查询中读取COMMITTED数据
  • 幻像读取 :从其他交易中的INSERTDELETE查询中读取COMMITTED数据

注意 :来自其他事务的DELETE语句在某些情况下导致非可重复读取的可能性非常低。不幸的是,当DELETE语句删除当前事务正在查询的同一行时,会发生这种情况。但这是一种罕见的情况,而且在每个表中有数百万行的数据库中更不可能发生这种情况。包含事务数据的表通常在任何生产环境中都具有高数据量。

此外,我们可能会发现UPDATES在大多数用例中可能更频繁,而不是实际的INSERT或DELETES(在这种情况下,不可重复读取的危险仅保留 - 幻像在这些情况下不可能读取)。这就是为什么UPDATES的处理方式与INSERT-DELETE不同,因此产生的异常也有不同的命名。

与INSERT-DELETE的处理相关的额外处理成本,而不仅仅是处理UPDATES。


不同isolation levels

的好处
  • READ_UNCOMMITTED什么都不阻止。这是零 隔离级别
  • READ_COMMITTED只阻止一个,即Dirty reads
  • REPEATABLE_READ防止两个异常:脏读和 不可重复的读取
  • SERIALIZABLE防止所有三个异常:脏读, 不可重复的读取和幻像读取

那么为什么不随时设置事务SERIALIZABLE?好吧,上面问题的答案是:SERIALIZABLE设置使事务非常,这是我们再次不想要的。

事实上,交易时间消耗的速度如下:

  

SERIALIZABLE > REPEATABLE_READ > READ_COMMITTED > READ_UNCOMMITTED

所以READ_UNCOMMITTED设置是最快的


摘要

实际上,我们需要分析用例并确定隔离级别,以便我们优化事务时间并防止大多数异常。

请注意,默认情况下,数据库具有REPEATABLE_READ设置。

答案 4 :(得分:7)

这两种隔离级别之间的实现存在差异 对于“不可重复读取”,需要行锁定 对于“幻读”,需要使用范围锁定,即使是表锁定 我们可以使用two-phase-locking协议来实现这两个级别。

答案 5 :(得分:4)

在具有不可重复读取的系统中,事务A的第二个查询的结果将反映事务B中的更新 - 它将看到新的数量。

在允许幻像读取的系统中,如果事务B要插入 ID为1的新行,则事务A将在执行第二个查询时看到新行;即幻像读取是不可重复读取的特殊情况。

答案 6 :(得分:1)

接受的答案最重要的是,所谓两者之间的区别实际上并不重要。

如果“一行被检索两次并且行内的值在读取之间不同”,则它们不是同一行(在正确的RDB中不是相同的元组说话),那么根据定义它也确实是“第二个查询返回的行集合与第一个“。

不同

关于“应该使用哪个隔离级别”的问题,您的数据对某人至关重要,在某个地方,Serializable是您唯一合理的选择。

答案 7 :(得分:0)

我认为Non-repeateable-read& amp;幻像读取。

不可重复意味着有两个交易A& B.如果B可以注意到A的修改,那么可能会发生脏读,所以我们让B在A提交后注意A的修改。

有一个新问题:我们让B在A提交后注意A的修改,这意味着A修改B所持有的行的值,有时B会再次读取该行,所以B将得到不同的新值我们第一次得到,我们称之为不可重复,处理问题,我们让B记住一些事情(因为我不知道将会记住什么)B开始。

让我们考虑新的解决方案,我们也可以注意到新的问题,因为我们让B记住一些东西,所以无论A中发生什么,B都不会受到影响,但是如果B想要将一些数据插入表中,B检查表以确保没有记录,但是这个数据已被A插入,因此可能会出现一些错误。我们称之为Phantom-read。

答案 8 :(得分:0)

不可重复读取是隔离级别,幻像读取(通过其他事务读取已提交的值)是一个概念(读取类型,例如脏读取或快照读取)。不可重复读取隔离级别允许幻像读取,但不允许脏读取或快照读取。

相关问题