读取提交和可重复读取之间的区别
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了读取提交和可重复读取之间的区别相关的知识,希望对你有一定的参考价值。
我认为上述隔离级别非常相似。有人可以用一些很好的例子来描述主要区别是什么?
Read committed是一个隔离级别,可以保证读取当前提交的任何数据。它只是限制读者看到任何中间的,未提交的,“脏”的读。 IT不承诺,如果事务重新发出读取,将找到相同的数据,数据在读取后可以自由更改。
可重复读取是一个更高的隔离级别,除了保证读取提交级别之外,它还保证任何数据读取都不会改变,如果事务再次读取相同的数据,它将找到先前读取的数据,不变,并可阅读。
可序列化的下一个隔离级别提供了更强大的保证:除了所有可重复读取保证之外,它还保证后续读取不会看到新数据。
假设你有一个带有C列的表T,其中有一行,比如它的值为'1'。并且考虑一下如下的简单任务:
BEGIN TRANSACTION;
SELECT * FROM T;
WAITFOR DELAY '00:01:00'
SELECT * FROM T;
COMMIT;
这是一个简单的任务,从表T发出两个读取,它们之间有1分钟的延迟。
- 在READ COMMITTED下,第二个SELECT可以返回任何数据。并发事务可以更新记录,删除它,插入新记录。第二个选择将始终显示新数据。
- 在REPEATABLE READ下,第二个SELECT保证看到第一次选择的行保持不变。在一分钟内,并发事务可以添加新行,但不能删除或更改现有行。
- 在SERIALIZABLE读取下,第二个选择保证看到与第一个完全相同的行。没有行可以更改,也不能删除,并且并发事务也不能插入新行。
如果你遵循上面的逻辑,你可以很快意识到SERIALIZABLE事务,虽然它们可能让你的生活变得轻松,但它总是完全阻止每个可能的并发操作,因为它们要求没有人可以修改,删除或插入任何行。 .Net System.Transactions
范围的默认事务隔离级别是可序列化的,这通常解释了导致的糟糕性能。
最后,还有SNAPSHOT隔离级别。 SNAPSHOT隔离级别与可序列化具有相同的保证,但不要求并发事务不能修改数据。相反,它迫使每个读者看到它自己的世界版本(它自己的'快照')。这使得它非常容易编程以及非常可扩展,因为它不会阻止并发更新。但是,这种好处需要付出代价:额外的服务器资源消耗。
补充读物:
- Isolation Levels in the Database Engine
- Concurrency Effects
- Choosing Row Versioning-based Isolation Levels
Repeatable Read
从事务开始就维护数据库的状态。如果在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
Read Committed
在事务的上下文中,您将始终检索最近提交的值。如果在session1中检索值,在session2中更新它,然后在session1again中检索它,您将获得在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
说得通?
根据我对这个帖子和@ remus-rusanu答案的阅读和理解,答案就是基于这个简单的场景:
有两个进程A和B.进程B正在读表X进程A正在写表X进程B再次读表X.
- ReadUncommitted:进程B可以从进程A读取未提交的数据,它可以根据B写入看到不同的行。根本没有锁
- ReadCommitted:进程B只能从进程A读取已提交的数据,并且它可以根据COMMITTED仅B写入看到不同的行。我们可以称之为Simple Lock吗?
- RepeatableRead:进程B将读取进程A正在执行的相同数据(行)。但是进程A可以更改其他行。行级块
- Serialisable:进程B将读取与以前相同的行,并且进程A无法在表中读取或写入。表级块
- 快照:每个进程都有自己的副本,他们正在处理它。每个人都有自己的观点
已经接受了答案的旧问题,但我喜欢考虑这两个隔离级别如何改变SQL Server中的锁定行为。这可能对那些像我一样调试死锁的人有所帮助。
READ COMMITTED(默认)
共享锁在SELECT中获取,然后在SELECT语句完成时释放。这就是系统如何保证不存在未提交数据的脏读。在SELECT完成之后和事务完成之前,其他事务仍然可以更改基础行。
可重复阅读
共享锁在SELECT中获取,然后仅在事务完成后才释放。这就是系统如何保证您在事务期间读取的值不会更改(因为它们在事务完成之前一直处于锁定状态)。
试图用简单的图解释这个疑问。
Read Committed:在此隔离级别,事务T1将读取事务T2提交的X的更新值。
可重复读取:在此隔离级别中,事务T1不会考虑事务T2提交的更改。
我认为这张图片也很有用,当我想快速记住隔离级别之间的差异时,它可以帮助我作为参考(感谢youtube上的kudvenkat)
请注意,重复读取可重复读取元组,但不是整个表。在ANSC隔离级别中,可能会出现幻像读取异常,这意味着读取具有相同where子句的表两次可能会返回不同的返回不同的结果集。从字面上看,它不可重复。
我对最初接受的解决方案的观察
在RR(默认mysql)下 - 如果tx已打开且已触发SELECT,则另一个tx无法删除属于先前READ结果集的任何行,直到上一个tx被提交(事实上,新tx中的delete语句将挂起)但是,下一个tx可以毫无困难地从表中删除所有行。顺便说一句,在之前的tx中的下一个READ仍将看到旧数据,直到它被提交。
以上是关于读取提交和可重复读取之间的区别的主要内容,如果未能解决你的问题,请参考以下文章