[英]Difference between non-repeatable read vs dirty read
从此oracle java 教程:
当事务 A 检索一行,事务 B 随后更新该行,事务 A 稍后再次检索同一行时,就会发生不可重复读取。 事务 A 两次检索同一行但看到不同的数据。
脏读和不可重复读有什么区别? 这不是一回事吗? 由于其他人的更新而读取错误的结果?
提前致谢。
完全相同的页面解释了脏读是什么:
访问尚未提交的更新值被视为脏读,因为该值有可能回滚到其先前的值。 如果您读取了稍后回滚的值,您将读取一个无效值。
因此,不可重复读包括读取两个不同的提交值,而脏读包括读取尚未提交的值。 很不一样。
从这里:-
当一个事务读取另一个未提交的事务写入的数据时,会发生脏读。 脏读的危险在于另一个事务可能永远不会提交,从而使原始事务具有“脏”数据。
当一个事务尝试两次访问相同的数据并且第二个事务在第一个事务的读取尝试之间修改数据时,就会发生不可重复读取。 这可能会导致第一个事务读取同一数据的两个不同值,从而导致原始读取不可重复。
一张图片值1000字。
在上图中,语句的流程是这样的:
这种异常只有 Read Uncommitted 隔离级别允许,并且由于对数据完整性的影响,大多数数据库系统提供更高的默认隔离级别。
我和你以前有同样的困惑。
在我阅读了您帖子中的答案后,我决定从 mysql doc 中找出答案。
从mysql阅读文档后,我认为让我们困惑的是understading角度。 我们认为“tran A 更改了一条记录而没有提交,而 tran B 前后读取了两条不同的数据,这确实是‘脏数据’和‘不可重复读取’”,我们混淆的是因为我们从两个交易行为的结果。
但是,正确的角度是:“脏读”是两笔交易,而“不可重复读”完全是一笔交易。
那是什么意思? 例如,如果您是交易,而我是您之后的交易。 你读了一个X,我把它更新为Y,然后你又读了一遍。
对我们来说,你读到了脏数据,因为我没有提交,也许我想回滚。 我让你阅读 dity 数据。
对于您自己,在您自己的事务中,您读取了两个不同的数据,这是不可重复的数据。
有点冗长。 可能有帮助。
参考文献:1. https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_dirty_read
2. https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_non_repeatable_read
脏读是在事务期间对未提交的插入、更新或删除数据的读取。
不可重复读取(模糊读取)是在事务期间读取已提交的更新数据。
我用MySQL和2 个命令提示符试验了脏读和不可重复读。
对于脏读和不可重复读的实验,我将READ-UNCOMMITTED
隔离级别设置为发生脏读和不可重复读:
SET GLOBAL transaction_isolation = 'READ-UNCOMMITTED';
SET SESSION transaction_isolation = 'READ-UNCOMMITTED';
而且,我用“id”和“name”创建了“person”表,如下所示:
ID | 姓名 |
---|---|
1 | 约翰 |
2 | 大卫 |
首先对于脏读,我使用SQL 查询执行了以下步骤:
流动 | 交易 1 (T1) | 交易 2 (T2) | 解释 |
---|---|---|---|
步骤1 | BEGIN; |
T1 开始。 | |
第2步 | BEGIN; |
T2 开始。 | |
第 3 步 | SELECT name FROM person WHERE id = 2; 2 大卫 |
T1 读作“大卫”。 | |
第4步 | UPDATE person SET name = 'Tom' WHERE id = 2; |
T2 将“大卫”更新为“汤姆”。 | |
第 5 步 | SELECT name FROM person WHERE id = 2; 2汤姆 |
T1 在 T2 提交之前读取“Tom”而不是“David”。*出现脏读!! |
|
第 6 步 | COMMIT; |
T2 提交。 | |
第 7 步 | COMMIT; |
T1 提交。 |
其次对于不可重复读取,我使用MySQL 查询执行了以下步骤:
流动 | 交易 1 (T1) | 交易 2 (T2) | 解释 |
---|---|---|---|
步骤1 | BEGIN; |
T1 开始。 | |
第2步 | BEGIN; |
T2 开始。 | |
第 3 步 | SELECT name FROM person WHERE id = 2; 2 大卫 |
T1 读作“大卫”。 | |
第4步 | UPDATE person SET name = 'Tom' WHERE id = 2; |
T2 将“大卫”更新为“汤姆”。 | |
第 5 步 | COMMIT; |
T2 提交。 | |
第 6 步 | SELECT name FROM person WHERE id = 2; 2汤姆 |
在 T2 提交后,T1 读取“Tom”而不是“David”。*发生不可重复读取!! |
|
第 7 步 | COMMIT; |
T1 提交。 |
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.