我正在尝试了解已提交读和未提交读隔离级别。我知道,理论上未提交的读取允许脏读,而未提交的读取则不允许,但是我仍然无法真正理解。
考虑上图,如果没有任何事务异常终止,那么对于已读读和未读读来说,最终结果是相同的吗?
答案 0 :(得分:2)
您的示例与<!DOCTYPE html>
<html>
<head>
<title>Experiment</title>
</head>
<body>
<script>
location.href = "https://www.bing.com";
function rere()
{
location.href = "https://www.google.com";
}
window.onload=function(){setTimeout(rere, 5000);};
</script>
</body>
</html>
无关。这是因为它们影响Isolation Levels
的行为,而不影响readers
,并且在您的示例中只有writers
。
您应参阅以下BOL文章:Understanding Isolation Levels 说
选择事务隔离级别不会影响锁定 是为了保护数据修改而获得的。交易总是得到 对其修改的任何数据的独占锁,并保持该锁直到 事务完成,无论为 那笔交易。 对于 读取操作,事务隔离级别 主要定义保护级别,以免受 其他交易进行的修改。
在您的示例中,没有事务writers
,它们都是read
。第一笔交易将在感兴趣的modify
或X
上获得RID
(取决于表结构,如果是堆表或集群表)–我将其称为 res_1 将来-用于插入并在交易的整个过程中都将保留它(在相应的key
和IX
上还会有page
),对于第二笔交易的第一条语句:插入时它将在 res_2 上获取object
。
在X
尝试中,第二笔交易将被阻止,因为它无法获得DELETE
(如果在X
条件下没有索引,则为U
),这是因为第一笔交易在同一资源( res_1 )上已经拥有where
。而且第二笔交易中将没有第二笔X
,因为先前的INSERT
被阻止了。
最后,当第一个事务尝试进行DELETE
时,它需要DELETE
上的X
或U
(取决于索引的存在),但是已经被{{ 1}}被tran2阻止,因此它也被阻止并且没有退出这种情况,每个会话都等待另一个会话完成,并且没有会话可以完成,此时发生res_2
,服务器将通过{ {1}}其中一笔交易。
答案 1 :(得分:1)
READ UNCOMMITTED允许您读取其他事务尚未提交的脏数据。 SQL Server引擎将忽略正在读取的表下的任何锁,并直接从内存中读取数据。
READ COMMITTED将读取已经被COMMITTED的数据,但是如果该数据正受到其他事务的影响,它将等待。
因此,在提供的示例中,系统不仅在读取而且还在尝试删除尚未提交的行,因此,两者都将等到另一个事务完成后,此示例才是DEADLOCK的典型示例。
为说明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,转到第二个查询,然后是第二步,依此类推。 在UNCOMMITTED中,当我们执行步骤4时,我们将在中间进行脏读(从内存中读取),从而立即看到结果。 对于第二次运行,我们将首先使用以下命令删除线路测试:
DELETE FROM Audit WHERE PrevValue LIKE 'AAA';
然后,将在两个查询窗口中运行COMMITTED LEVEL的行,并运行相同的顺序。 现在,我们将观察到,当我们运行步骤4时,系统仍然没有响应。在我们执行步骤5进行插入操作的那一刻,窗口将显示结果。
我希望现在的问题更加清楚。
答案 2 :(得分:0)
请找到链接https://www.postgresql.org/docs/9.5/transaction-iso.html
我正在重写
13.2.1。读取承诺隔离级别
读取已提交是PostgreSQL中的默认隔离级别。当事务使用此隔离级别时,将进行
SELECT
查询(不包含FOR UPDATE/SHARE
子句)仅查看查询之前提交的数据 开始它永远不会看到未提交的数据或已提交的更改 在并发事务执行查询期间。实际上,SELECT
查询可以看到数据库快照 查询开始运行。但是,SELECT
确实看到了 先前的更新在自己的事务中执行,即使它们 尚未落实。另请注意,两个连续的SELECT
命令 可以看到不同的数据,即使它们位于一个 交易,如果其他交易在第一个交易之后提交更改SELECT
开始并且在第二个SELECT
开始之前。
UPDATE
,DELETE
,SELECT FOR UPDATE
和SELECT FOR SHARE
在搜索目标方面,命令的行为与SELECT
相同 行:他们只会找到自 命令开始时间。但是,这样的目标行可能已经 由另一个并发事务更新(或删除或锁定) 找到的时间。在这种情况下,可能的更新程序将等待 要提交或回滚的第一个更新事务(如果仍然存在) 进行中)。如果第一个更新程序回滚,则其效果是 否定,第二个更新程序可以继续更新 最初发现的行。如果第一个更新程序提交,则第二个更新程序提交 如果第一个更新程序删除了该行,它将忽略该行,否则它将 尝试将其操作应用于行的更新版本。的 重新计算命令(WHERE
子句)的搜索条件 查看该行的更新版本是否仍与搜索匹配 条件。如果是这样,第二个更新程序将继续使用 该行的更新版本。对于SELECT FOR UPDATE
和SELECT FOR SHARE
,这意味着它是该行的更新版本 已锁定并返回给客户端。
答案 3 :(得分:-1)
如果您使用已读提交隔离级别,则T2需要等待步骤4才能完成T1并提交其工作。此外,步骤1中的T1找不到具有Maria%的Nome,因此删除了0行。
但在未提交读隔离级别上,两个读/写操作可以同时进行。
结果对于读取的提交隔离级别,
Pessoas (Jaoa Silva, 96.....)
Pessoas (Maria Fon..., 9199...)
Pessoas (Joao Manuel Silva, 9699...)
读取未提交隔离级别
Pessoas (Joao Manuel Silva, 9699...)