非可重复读取和幻像读取之间有什么区别?
我已阅读Isolation (database systems) article from Wikipedia,但我有些疑惑。在下面的示例中,会发生什么:不可重复读取和幻像读取?
交易ASELECT 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
另一个疑问是,在上面的例子中,应该使用哪个隔离级别?为什么?
答案 0 :(得分:130)
From Wikipedia(其中有很好的详细示例):
发生不可重复的读取,当在事务过程中,一行被检索两次,并且行内的值在读取之间不同。
和
当在事务过程中执行两个相同的查询,并且第二个查询返回的行集合与第一个查询不同时,会发生幻像读取。
简单示例:
select sum(x) from table;
将返回不同的结果,即使已添加或删除行,也不会更新任何受影响的行本身。在上面的例子中,要使用哪个隔离级别?
您需要什么样的隔离级别取决于您的应用程序。 “更好”的隔离级别(例如降低的并发性)成本很高。
在您的示例中,您不会进行幻像读取,因为您只从一行(由主键标识)中选择。您可以进行不可重复的读取,因此如果这是一个问题,您可能希望具有阻止它的隔离级别。在Oracle中,事务A也可以发出SELECT FOR UPDATE,然后事务B在A完成之前不能更改行。
答案 1 :(得分:100)
我想考虑的一个简单方法是:
非可重复和幻像读取都与来自不同事务的数据修改操作有关,这些操作在您的事务开始后提交,然后由您的事务读取。
不可重复读取是指您的交易从另一个交易中读取提交更新的时间。现在,同一行的值与您的交易开始时的值不同。
幻像读取类似,但是从另一个事务中读取已提交的 INSERTS 和/或 DELETES 时。自您开始交易以来,新的行或行已经消失。
脏读取类似到非可重复和幻像读取,但与读取UNCOMMITTED数据有关,并且在读取来自另一个事务的UPDATE,INSERT或DELETE时发生,而另一个事务具有尚未提交数据。它正在读取“进行中”数据,这些数据可能不完整,可能永远不会被提交。
答案 2 :(得分:20)
如this article中所述,不可重复读取异常如下所示:
在关于{strong>幻影阅读的this article中,您可以看到这种异常可能发生如下:
因此,尽管不可重复读取适用于单行,但虚拟读取是关于满足给定查询过滤条件的一系列记录。
答案 3 :(得分:10)
UPDATE
查询中读取COMMITTED数据INSERT
或DELETE
查询中读取COMMITTED数据注意 :来自其他事务的DELETE语句在某些情况下导致非可重复读取的可能性非常低。不幸的是,当DELETE语句删除当前事务正在查询的同一行时,会发生这种情况。但这是一种罕见的情况,而且在每个表中有数百万行的数据库中更不可能发生这种情况。包含事务数据的表通常在任何生产环境中都具有高数据量。
此外,我们可能会发现UPDATES在大多数用例中可能更频繁,而不是实际的INSERT或DELETES(在这种情况下,不可重复读取的危险仅保留 - 幻像在这些情况下不可能读取)。这就是为什么UPDATES的处理方式与INSERT-DELETE不同,因此产生的异常也有不同的命名。
与INSERT-DELETE的处理相关的额外处理成本,而不仅仅是处理UPDATES。
那么为什么不随时设置事务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)
不可重复读取是隔离级别,幻像读取(通过其他事务读取已提交的值)是一个概念(读取类型,例如脏读取或快照读取)。不可重复读取隔离级别允许幻像读取,但不允许脏读取或快照读取。