不一致分析和不可重复读取之间有什么区别?

时间:2018-05-15 14:47:10

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

我已经看到很多与不一致的分析和脏读取以及对脏读的不可重复读取的比较,但我似乎无法掌握不一致(不正确)分析与不可重复分析之间的区别读?

有没有更好的方法来解释这一点。

我的困惑在于,它们都是事务的多个读取部分,其中第二个(或第三个)事务进行提交的更新。

分析错误 - 第二个事务读取的数据由进行更改的事务提交。不一致的分析涉及同一行的多次读取(两次或多次),每次信息被另一次事务更改,从而每次产生不同的结果,因此不一致。

在哪里

不可重复读取 在一个事务尝试两次访问相同数据并且第二个事务在第一个事务读取之间修改数据时发生尝试。这可能导致第一个事务为同一数据读取两个不同的值,导致原始读取不可重复。

我无法弄清楚它们有何不同。 谢谢。

1 个答案:

答案 0 :(得分:0)

在我看来,以下是不一致分析的示例,但不是不可重复读取的示例。 该示例使用银行帐户表:

CREATE TABLE ACCOUNT(
    NO NUMERIC(10) NOT NULL PRIMARY KEY,
    BALANCE NUMERIC(9,2) NOT NULL);
INSERT INTO ACCOUNT VALUES (1, 100.00);
INSERT INTO ACCOUNT VALUES (2, 200.00);

出于性能原因,银行有另一个表冗余存储所有帐户余额的总和(因此,该表始终只有一行):

CREATE TABLE TOTAL(AMOUNT NUMERIC(9,2) NOT NULL);
INSERT INTO TOTAL SELECT SUM(BALANCE) FROM ACCOUNT;

假设事务 A 想要检查冗余和是否确实正确。它首先计算帐户余额的总和:

START TRANSACTION; -- PostgreSQL and SQL Standard, switches autocommit off
SELECT SUM(BALANCE) FROM ACCOUNT;

现在账户 1 的所有者存入了 50 美元。这是在事务 B 中完成的:

START TRANSACTION;
UPDATE ACCOUNT SET BALANCE = BALANCE + 50 WHERE NO = 1;
UPDATE TOTAL SET AMOUNT = AMOUNT + 50;
COMMIT;

最后,事务 A 继续读取冗余和:

SELECT AMOUNT FROM TOTAL;

它会看到增加的值,这与它计算的总和不同(可能导致误报)。

在这个例子中,事务 A 没有读取任何表行两次,因此这不可能是不可重复读取。但是,它没有看到唯一的数据库状态——部分信息来自事务 B 更新前的旧状态,部分信息来自更新后的新状态。

但这肯定与不可重复读取非常相关:如果 A 再次读取了 ACCOUNT 行,这将是不可重复读取。似乎防止不可重复读取的相同内部机制也防止了这个问题:可以将读取行保持锁定直到事务结束,或者对事务开始时的版本使用多版本并发控制。

然而,这里也有一个很好的解决方案,即在一个查询中获取所有数据。至少 Oracle 和 PostgreSQL 保证只针对数据库的一种状态评估单个查询:

SELECT SUM(BALANCE) AS AMOUNT, 'SUM' AS PART FROM ACCOUNT
UNION ALL
SELECT AMOUNT, 'TOTAL' AS PART FROM TOTAL;

在具有读取和写入的事务调度的正式模型中,这看起来也与不可重复读取非常相似:首先 A 执行读取(x),然后 B 执行写入(x)、写入(y),然后是 A读(y)。如果只涉及单个对象,这将是不可重复读取。