use*_*722 137 database oracle transactions transaction-isolation isolation-level
不可重复读和幻读之间有什么区别?
我已经阅读了维基百科的隔离(数据库系统)文章,但我有一些疑问.在下面的例子中,会发生什么:不可重复的读取和幻像读取?
交易A.SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1
1----MIKE------29019892---------5000
UPDATE USERS SET amount=amount+5000 where ID=1 AND accountno=29019892;
COMMIT;
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1
另一个疑问是,在上面的例子中,应该使用哪个隔离级别?为什么?
Thi*_*ilo 147
来自维基百科(其中有很多详细的例子):
发生不可重复的读取,当在事务过程中,行被检索两次并且行内的值在读取之间不同.
和
当在事务过程中执行两个相同的查询,并且第二个查询返回的行集合与第一个查询不同时,会发生幻像读取.
简单的例子:
select sum(x) from table;如果已添加或删除行,即使没有更新受影响的行本身也将返回不同的结果.在上面的例子中,要使用哪个隔离级别?
您需要什么隔离级别取决于您的应用程序."更好"的隔离级别(例如降低的并发性)成本很高.
在您的示例中,您将不会进行幻像读取,因为您只选择单行(由主键标识).您可以进行不可重复的读取,因此如果这是一个问题,您可能希望具有阻止它的隔离级别.在Oracle中,事务A也可以发出SELECT FOR UPDATE,然后事务B在A完成之前不能更改行.
Bat*_*ech 114
我想要考虑的一个简单方法是:
非可重复和幻像读取都与来自不同事务的数据修改操作有关,这些操作在事务开始后提交,然后由您的事务读取.
不可重复的读取是指您的事务从另一个事务读取提交的UPDATES.现在,同一行的值与您的事务开始时的值不同.
幻像读取类似,但是从提交的INSERTS读取和/或从另一个事务中读取DELETES时.自开始事务以来,有新的行或行已消失.
脏读类似于不可重复和幻像读取,但与读取UNCOMMITTED数据有关,并且在读取来自另一个事务的UPDATE,INSERT或DELETE,而另一个事务尚未提交数据时发生.它正在读取"进行中"数据,这些数据可能不完整,可能永远不会实际提交.
Vla*_*cea 25
如本文所述,不可重复读取异常如下所示:
在这篇关于Phantom Read的文章中,您可以看到此异常可能发生如下:
因此,虽然不可重复读取适用于单个行,但是Phantom Read是一系列满足给定查询过滤条件的记录.
小智 16
脏读:从另一个事务中读取未提供的数据.
不可重复读取:从另一个事务中读取来自UPDATE查询的COMMITED数据.
幻像读取:从另一个事务中读取来自INSERT或DELETE查询的COMMITED数据.
请注意,UPDATES在某些用例中可能是更频繁的工作,而不是实际的INSERT或DELETES - 在这种情况下,不可重复读取的危险仍然存在 - 在这些情况下不可能进行幻读.这就是为什么UPDATES与INSERT-DELETE的区别对待,有关的异常也有不同的命名.
处理INSERT-DELETES还需要额外的处理成本,而不仅仅是处理UPDATES.
隔离级别TRANSACTION_READ_UNCOMMITTED不会阻止任何操作.它的零隔离级别.
隔离级别TRANSACTION_READ_COMMITTED只能阻止一个,即.脏读.
隔离级别TRANSACTION_REPEATABLE_READ可防止两个异常:脏读和不可重复读.
隔离级别TRANSACTION_SERIALIZABLE可防止所有三个异常:脏读,不可重复读和幻读.
那么为什么不随时设置事务SERIALIZABLE?
好吧,上面问题的答案是:SERIALIZABLE设置使交易非常慢,我们再次不想要.
事实上,交易时间消耗的速度如下:
SERIALIZABLE> REPEATABLE_READ> READ_COMMITTED> READ_UNCOMMITTED.
所以READ_UNCOMMITTED设置是最快的.
实际上,我们需要分析用例并确定隔离级别,以便我们优化事务时间并防止大多数异常.
请注意,默认情况下,数据库具有REPEATABLE_READ设置.
小智 10
不可重复读(模糊读)是指一个事务至少读取同一行两次,但第一次和第二次读取同一行的数据不同,因为其他事务同时(并发)更新同一行的数据并提交。
幻读是指一个事务至少读取同一个表两次,但第一次和第二次读取同一个表的行数不同,因为其他事务同时(并发)插入或删除行并提交。
我用MySQL和2个命令提示符实验了不可重复读和幻读。
对于不可重复读和幻读的实验,我设置READ COMMITTED隔离级别以发生不可重复读和幻读:
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
并且,我使用 和 创建了表格,person如下所示。idname
person桌子:| ID | 姓名 | 
|---|---|
| 1 | 约翰 | 
| 2 | 大卫 | 
首先,对于不可重复读取,我使用MySQL 查询执行了以下步骤:
| 流动 | 交易1(T1) | 交易2(T2) | 解释 | 
|---|---|---|---|
| 步骤1 | BEGIN; | T1开始。 | |
| 第2步 | BEGIN; | T2开始。 | |
| 步骤3 | SELECT * FROM person WHERE id = 2;2 大卫 | T1 读取 David。 | |
| 步骤4 | UPDATE person SET name = 'Tom' WHERE id = 2; | T2 更新 David至Tom. | |
| 步骤5 | COMMIT; | T2 提交。 | |
| 步骤6 | SELECT * FROM person WHERE id = 2;2 汤姆 | T1 读取 Tom而不是DavidT2 提交之后。*发生不可重复读!! | |
| 步骤7 | COMMIT; | T1 提交。 | 
其次,对于幻读,我使用MySQL 查询执行了以下步骤:
| 流动 | 交易1(T1) | 交易2(T2) | 解释 | 
|---|---|---|---|
| 步骤1 | BEGIN; | T1开始。 | |
| 第2步 | BEGIN; | T2开始。 | |
| 步骤3 | SELECT * FROM person;约翰一书 大卫二书 | T1 读取 2 行。 | |
| 步骤4 | INSERT INTO person VALUES (3, 'Tom'); | 3T2 将带有和 的行插入Tom到person表中。 | |
| 步骤5 | COMMIT; | T2 提交。 | |
| 步骤6 | SELECT * FROM person;约翰一书 大卫二书 汤姆三书 | T2 提交后,T1 读取 3 行而不是 2 行。 *出现幻读!! | |
| 步骤7 | COMMIT; | T1 提交。 | 
在具有不可重复读取的系统中,事务 A 的第二次查询的结果将反映事务 B 中的更新——它将看到新的金额。
在允许幻读的系统中,如果事务 B 要插入ID = 1 的新行,事务 A 将在执行第二个查询时看到新行;即幻读是不可重复读的特例。
| 归档时间: | 
 | 
| 查看次数: | 78799 次 | 
| 最近记录: |