Read Committed 与 Read Uncommitted 如果两个事务都不回滚

Read Committed vs Read Uncommited if both transaction do not rollback

我正在尝试了解读取已提交和读取未提交的隔离级别。我知道 theoreticay read uncommitted 允许脏读而 read committed 不允许,但我还是不太明白。

考虑上图,如果 none 的事务被中止,那么读已提交和读未提交的最终结果是否相同?

如果您使用读提交隔离级别,T2 需要在第 4 步等待 T1 完成并提交其工作。此外,步骤 6 中的 T1 找不到带有 Maria% 的 Nome,因此删除 0 行。

但是在读取未提交隔离级别上,两个 read/write 操作可以同时完成。

Result For read committed isolation level,

Pessoas (Jaoa Silva, 96.....)
Pessoas (Maria Fon..., 9199...)
Pessoas (Joao Manuel Silva, 9699...)

而读取未提交隔离级别

Pessoas (Joao Manuel Silva, 9699...)

READ UNCOMMITTED 可以读取其他事务未提交的脏数据。 SQL 服务器引擎忽略正在读取的 table 下的任何锁并直接从内存中读取数据。

READ COMMITTED 将读取已经提交的数据,但如果数据正受到其他事务的影响,则会等待。

因此,在提供的示例中,系统不仅在读取而且还在尝试删除尚未提交的行,因此,两者都将等待另一个事务完成,因此,该示例是一个典型示例僵局。

为了说明 COMMITTED 与 UNCOMMITTED 之间的区别,我将向您展示一个简单明了的示例,我们将在两种模式下 运行 两次。

-- Query Window 1
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;  -- Prepare for first Run
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;    -- Prepare for second Run

BEGIN TRANSACTION                                   -- Step 1
INSERT INTO Audit (ProductID, PrevValue, NewValue, ChangedBy)   
    VALUES (1, 'AAA', 'aaa', SYSTEM_USER);          -- Step 3
COMMIT TRANSACTION                                  -- Step 5

-- Query Window 2
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;  -- Prepare for first Run
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;    -- Prepare for second Run

BEGIN TRANSACTION                           -- Step 2
SELECT * FROM Audit WHERE PrevValue = 'AAA' -- Step 4
COMMIT TRANSACTION                          -- Step 6

我们必须先 运行 两个查询中的 UNCOMMITTED LEVEL 行,然后转到第一个,运行 第 1 步,转到第二个,第 2 步,依此类推。 在 UNCOMMITTED 中,当我们 运行 第 4 步时,我们将立即看到结果,因为我们正在进行脏读(从内存)。 对于第二个 运行,我们将首先删除线路测试:

DELETE FROM Audit WHERE PrevValue LIKE 'AAA';   

然后,运行 COMMITTED LEVEL 行将在查询 windows 和 运行 相同的序列中。 现在我们将观察到,当我们 运行 步骤 4 系统仍然没有响应。就在我们 运行 第 5 步提交插入的那一刻 window 将显示结果。

我希望现在的问题更清楚了。

您的示例与 Isolation Levels 无关。这是因为它们影响 readers 行为,而不是 writers,并且在您的示例中只有 writers.

你应该参考这篇 BOL 文章:Understanding Isolation Levels 那说

Choosing a transaction isolation level doesn't affect the locks that are acquired to protect data modifications. A transaction always gets an exclusive lock on any data it modifies and holds that lock until the transaction completes, regardless of the isolation level set for that transaction. For read operations, transaction isolation levels primarily define the level of protection from the effects of modifications made by other transactions.

在您的交易示例 none 中 read,它们都 modify。第一个事务将在感兴趣的 RIDkey 上获取 X(取决于 table 结构,如果它是堆或集群 table)——我会将来称它为 res_1——用于插入,并将在整个交易期间保持它(它在相应的 [=20= 上也会有 IX ]和object),第二个事务的第一条语句也是一样:插入时会在res_2上获取X

DELETE 尝试时,第二个事务将被阻止,因为它无法获得 X(或 U,以防在 where 条件下没有索引),这是因为第一个事务在同一资源 (res_1) 上已经有 X。并且第二个交易中不会有第二个INSERT,因为之前的DELETE被阻塞了。

最后,当第一个事务尝试其 DELETE 时,它需要 XU(取决于索引是否存在)res_2,但它已被阻止X 由 tran2,所以它也被阻止并且没有退出这种情况,每个会话都等待另一个会话完成并且没有会话可以完成,此时发生 deadlock 并且服务器将解决它通过rolling back其中一笔交易。

请找到linkhttps://www.postgresql.org/docs/9.5/transaction-iso.html

我是re-writing

13.2.1. Read Committed Isolation Level

Read Committed is the default isolation level in PostgreSQL. When a transaction uses this isolation level, a SELECT query (without a FOR UPDATE/SHARE clause) sees only data committed before the query began; it never sees either uncommitted data or changes committed during query execution by concurrent transactions. In effect, a SELECT query sees a snapshot of the database as of the instant the query begins to run. However, SELECT does see the effects of previous updates executed within its own transaction, even though they are not yet committed. Also note that two successive SELECT commands can see different data, even though they are within a single transaction, if other transactions commit changes after the first SELECT starts and before the second SELECT starts.

UPDATE, DELETE, SELECT FOR UPDATE, and SELECT FOR SHARE commands behave the same as SELECT in terms of searching for target rows: they will only find target rows that were committed as of the command start time. However, such a target row might have already been updated (or deleted or locked) by another concurrent transaction by the time it is found. In this case, the would-be updater will wait for the first updating transaction to commit or roll back (if it is still in progress). If the first updater rolls back, then its effects are negated and the second updater can proceed with updating the originally found row. If the first updater commits, the second updater will ignore the row if the first updater deleted it, otherwise it will attempt to apply its operation to the updated version of the row. The search condition of the command (the WHERE clause) is re-evaluated to see if the updated version of the row still matches the search condition. If so, the second updater proceeds with its operation using the updated version of the row. In the case of SELECT FOR UPDATE and SELECT FOR SHARE, this means it is the updated version of the row that is locked and returned to the client.