“已提交读”和“可重复读”之间的区别


245

我认为上述隔离级别是如此相似。有人可以用一些很好的例子来描述主要区别是什么吗?


3
您应该扩展问题并为您指的是什么“隔离级别”(Java等)添加标签。“隔离级别”是一个有点模棱两可的术语,您显然正在要求针对特定环境的答案。
jesup 2010年

Answers:


564

提交的读取是隔离级别,可确保读取当前已提交的任何数据。它只是限制了读者看不到任何中间的,未提交的“脏”读物。它不保证如果事务重新发出读取,将找到相同的数据,则数据在读取后可以自由更改。

可重复读是一个较高的隔离级别,除了保证已提交读级别外,它还保证任何读取的数据都不能更改,如果事务再次读取相同的数据,它将发现原先读取的数据保持不变,可供阅读。

接下来的隔离级别,序列化,使得一个更强大的保障:除了所有重复的读取担保,这也保证了没有的数据可以通过后续读取待观察。

假设您有一个表T,其中的C列中有一行,说它的值为'1'。考虑一下您有一个简单的任务,如下所示:

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

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

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

如果遵循上述逻辑,您会很快意识到,尽管SERIALIZABLE事务使您的生活变得轻松,但它们始终完全阻止所有可能的并发操作,因为它们不需要任何人可以修改,删除或插入任何行。.Net System.Transactions范围的默认事务隔离级别是可序列化的,这通常可以解释所导致的糟糕性能。

最后,还有SNAPSHOT隔离级别。SNAPSHOT隔离级别提供与可序列化相同的保证,但是不要求任何并发事务都不能修改数据。相反,它强迫每个读者看到自己的世界版本(这是自己的“快照”)。由于它不阻止并发更新,因此可以很容易地针对它进行编程以及可扩展性。但是,这种好处是有代价的:额外的服务器资源消耗。

补充读物:


24
我认为上面的可重复读取有一个错误:您说无法删除或更改现有行,但是我认为可以删除或更改它们,因为可重复读取只是读取“快照”而不是实际数据。在docsdev.mysql.com/doc/refman/5.0/en/…中:“同一事务中的所有一致读取均读取由第一次读取建立的快照。”
德里克·里兹

2
@Derek Litz我的意思是,您说的是:在进行交易时,可以通过第三方更改数据,但读取后仍会看到“旧的”原始数据,就像未进行更改一样位置(快照)。
Programster

5
@Cornstalks。是的,可以从删除(或插入)中进行幻影读取。是的,幻像读取可以以可重复的读取隔离方式发生(仅限插入)。否,无法以可重复的读取隔离方式进行从删除操作产生的幻像读取。测试一下。我所说的与您引用的文档没有矛盾。
AndyBrown 2014年

4
@Cornstalks NP。我只是提到它,是因为我不是100%确定自己,因此必须深入研究以确保谁是对的!而且我不希望将来的读者产生误导。重新保留评论,最好按照建议保留。我敢肯定,对这个细节水平感兴趣的其他人将足够阅读所有评论!
AndyBrown 2014年

12
感谢您不要删除您的评论。讨论有助于连接更多点。
乔什(Josh)

68

可重复读

从事务开始就维护数据库的状态。如果您在会话1中检索到一个值,则在会话2中更新该值,然后在会话1中再次检索该值将返回相同的结果。读取是可重复的。

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 2008中尝试使用“设置隔离级别可重复读取”来进行可重复读取。创建了两个sql查询窗口。但是没有用。为什么?
Aditya Bokade 2013年

1
为什么第二届会议1仍然读出亚伦?session2的事务是否已完成并提交?我知道这个年龄很大,但也许有人可以阐明。
Sonny Childs,2015年

9
我认为“可重复读取”将阻塞第二个会话,直到第一个会话提交为止。所以这个例子是错误的。
Nighon'7

4
在“可重复读”的情况下,会话1读取行时,它将放置一个共享锁,这将不允许任何“互斥”锁(到会话2)进行更新,因此无法更新数据。
塔赫

我认为在更新两个事务之间的共享行时,SQL Server和MySQL的行为有所不同
user2488286

23

根据我对这个线程的阅读和理解,答案很简单,而@ remus-rusanu答案则基于以下简单场景:

进程A和B有两个。进程B正在读取表X进程A正在写入表X进程B正在再次读取表X。

  • ReadUncommitted:进程B可以从进程A读取未提交的数据,并且基于B的写入可以看到不同的行。完全没有锁
  • ReadCommitted:进程B只能从进程A读取已提交的数据,并且基于仅COMMITTED B的写入,它可以看到不同的行。我们可以称之为简单锁吗?
  • RepeatableRead:无论进程A在做什么,进程B都将读取相同的数据(行)。但是进程A可以更改其他行。行级块
  • 可序列化的:进程B将读取与以前相同的行,并且进程A无法在表中读取或写入。表级块
  • 快照:每个进程都有自己的副本,并且正在使用它。每个人都有自己的看法

15

已有一个已经接受的答案的老问题,但是我想考虑这两个隔离级别如何改变SQL Server中的锁定行为。这对于像我一样调试死锁的人可能会有所帮助。

读取已提交(默认)

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

可重复读取

共享锁在SELECT中获取,然后仅在事务完成后才释放。这是系统可以保证您读取的值在事务期间不会更改的方法(因为在事务完成之前它们将保持锁定状态)。


13

试图用简单的图表解释这个疑问。

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

阅读已提交

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

在此处输入图片说明


1

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

在此处输入图片说明


0

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


-1

我对最初接受的解决方案的观察。

在RR(默认mysql)下-如果一个tx已打开并且SELECT已被激发,则另一个tx在提交前一个tx之前,不能删除属于先前READ结果集的任何行(实际上,新tx中的delete语句只会挂起) ,但是下一个TX可以毫无问题地删除表中的所有行。顺便说一句,前一个TX中的下一个READ仍将看到旧数据,直到将其提交为止。


2
您可能希望将其放在评论部分,以便答复者得到通知。这样,他将能够回应您的观察并在需要时进行更正。
RBT
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.