区别“读承诺”;和“可重复阅读”;

我认为上述隔离级别是如此相似。有人能举个例子说明一下主要的区别是什么吗?

196654 次浏览

Read committed是一个隔离级别,它保证当前读取的任何数据都是承诺。它只是限制读者看到任何中间的、未提交的、“脏”的读取。它不保证如果事务重新发出read,将找到相同数据,数据在读取后可以自由更改。

可重复读取是一种更高的隔离级别,除了保证读取提交级别外,它还保证任何读取不能改变的数据,如果事务再次读取相同的数据,它将发现先前读取的数据在适当的位置,没有变化,并且可以读取。

下一个隔离级别serializable提供了更强的保证:除了所有可重复读取的保证之外,它还保证了No new data可以被后续的读取看到。

假设你有一个表T,其中有一个列C,其中有一行,它的值是'1'。假设你有一个简单的任务,就像下面这样:

BEGIN TRANSACTION;
SELECT * FROM T;
WAITFOR DELAY '00:01:00'
SELECT * FROM T;
COMMIT;

这是一个简单的任务,从表T中读取两次,两次之间的延迟为1分钟。

  • 在READ COMMITTED下,第二个SELECT可能返回任何数据。并发事务可以更新记录、删除记录、插入新记录。第二个选择将始终看到数据。
  • 在REPEATABLE READ下,第二个SELECT保证至少显示从第一个SELECT 不变返回的行。在这一分钟内,并发事务可以添加新的行,但不能删除或更改现有的行。
  • 在SERIALIZABLE读取下,第二个select保证看到与第一个相同的完全行。并发事务不能更改或删除任何行,也不能插入任何新行。

如果你遵循上面的逻辑,你很快就会意识到SERIALIZABLE事务,虽然它们可能会让你的生活更容易,但它们总是完全阻止每一个可能的并发操作,因为它们要求任何人都不能修改、删除或插入任何行。. net System.Transactions作用域的默认事务隔离级别是可序列化的,这通常解释了由此导致的糟糕性能。

最后,还有SNAPSHOT隔离级别。SNAPSHOT隔离级别提供了与可序列化性相同的保证,但不要求任何并发事务都不能修改数据。相反,它迫使每个读者看到自己版本的世界(自己的“快照”)。这使得编程非常容易,也非常可伸缩,因为它不会阻塞并发更新。然而,这种好处是有代价的:额外的服务器资源消耗。

补充阅读:

可重复读取

数据库的状态从事务开始时开始维护。如果在session1中检索一个值,然后在session2中更新该值,在session1中再次检索它将返回相同的结果。读取是可重复的。

session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron


session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;


session1> SELECT firstname FROM names WHERE id = 7;
Aaron

读过承诺

在事务的上下文中,您将始终检索最近提交的值。如果您在session1中检索一个值,在session2中更新它,然后再次在session1中检索它,您将得到在session2中修改后的值。它读取最后提交的行。

session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron


session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;


session1> SELECT firstname FROM names WHERE id = 7;
Bob

有道理吗?

这个老问题已经有了一个公认的答案,但我喜欢从如何改变SQL Server中的锁定行为的角度来考虑这两个隔离级别。这可能对那些像我一样调试死锁的人有帮助。

READ COMMITTED(默认)

在SELECT中获取共享锁,然后释放当SELECT语句完成时。这就是系统如何保证没有未提交数据的脏读。其他事务仍然可以在SELECT完成之后和事务完成之前更改基础行。

可重复读取

在SELECT中获取共享锁,然后释放只有在交易完成之后。这就是系统如何保证您读取的值在事务期间不会更改(因为它们在事务完成之前保持锁定)。

我对初始接受解的观察。

在RR下(默认mysql) -如果tx打开并且SELECT已经触发,另一个tx不能删除属于前一个READ结果集的任何行,直到前一个tx被提交(事实上,新tx中的delete语句只会挂起),然而下一个tx可以毫不麻烦地从表中删除所有行。顺便说一下,上一个tx中的下一次READ仍然会看到旧数据,直到它被提交。

根据我对这个帖子的阅读和理解,@remus-rusanu的答案是基于这个简单的场景:

有两个事务A和B。 事务B正在读取表X 事务A正在写表X 事务B在表x中再次读取
  • ReadUncommitted:事务B可以从事务A读取未提交的数据,并且它可以看到基于B写入的不同行。根本没有锁
  • ReadCommitted:事务B只能从事务A中读取已提交的数据,并且它可以看到基于committed ONLY B写入的不同行。我们可以叫它简单锁吗?
  • RepeatableRead:无论事务A正在做什么,事务B将读取相同的数据(行)。但是事务A可以改变其他行。行级别
  • Serialisable:事务B将读取与之前相同的行,事务A不能在表中读写。表级块
  • 快照:每个事务都有自己的副本,他们正在处理它。每个人都有自己的观点

试图用简单的图表来解释这种怀疑。

读承诺:在此隔离级别中,事务T1将读取事务T2提交的X的更新值。

Read Committed

可重复读:在此隔离级别中,事务T1不会考虑事务T2提交的更改。

enter image description here

我认为这张照片也很有用,当我想快速记住隔离级别之间的差异时,它可以帮助我作为参考(感谢youtube上的kudvenkat)

enter image description here

请注意,可重复读中的可重复的涉及元组,而不是整个表。在ANSC隔离级别中,幻像读异常可能发生,这意味着读取带有相同where子句的表两次可能返回不同的返回不同的结果集。字面上,它不是可重复的