读取提交和可重复读取之间的区别

我觉得上面的隔离水平是如此相似。 有人可以用一些很好的例子来描述它的主要区别是什么?

读提交是一个隔离级别,保证读取的任何数据读取在此刻被读取。 它只是限制读者看到任何中间的,不承诺的,“脏”的阅读。 IT不承诺如果事务重新发布读取,将发现相同的数据,数据读取后可以自由改变。

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

下一个隔离级别,可序列化,更强有力的保证:除了所有可重复读取保证外,还保证后续读取不会看到新的数据

假设你有一个表C,里面有一列C,它的值是'1'。 并考虑你有一个简单的任务,如下所示:

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

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

  • 在READ COMITTED下,第二个SELECT可以返回任何数据。 并发事务可以更新logging,删除它,插入新的logging。 第二个select将始终看到新的数据。
  • 在REPEATABLE READ下,第二个SELECT保证在第一个select的行中看到未改变的行 。 在一分钟内可以通过并发事务添加新行,但是现有行不能被删除也不能改变。
  • 在SERIALIZABLE读取下,第二个select保证看到与第一个完全相同的行。 没有行可以更改,也不能删除,也不能由并发事务插入新行。

如果你遵循上面的逻辑,你可以很快意识到SERIALIZABLE事务虽然可以使你的生活变得简单,但总是完全阻塞每一个可能的并发操作,因为它们要求比任何人都不能修改,删除或插入任何行。 .Net System.Transactions作用域的缺省事务isolationlevel是可序列化的,这通常解释了结果的糟糕performance。

最后,还有SNAPSHOT隔离级别。 SNAPSHOT隔离级别与可序列化保证了相同的保证,但不是要求没有并发事务可以修改数据,而是让每个读者都看到它自己的世界版本(它自己的“快照”)。 这使得编程非常容易,可扩展性非常好,因为它不会阻止并发更新,但它当然是有代价的,价格是额外的服务器资源消耗。

补充内容:

  • 数据库引擎中的隔离级别
  • 并发效应
  • select基于行版本的隔离级别

可重复的阅读

数据库的状态从事务开始时被维护。 如果您在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中更新它,然后在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 

说得通?

老问题,已经有了一个可以接受的答案,但是我喜欢根据它们如何改变SQL Server中的locking行为来考虑这两个隔离级别。 这可能对那些像我一样debugging死锁的人有帮助。

READ COMMITTED(默认)

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

可重复阅读

共享锁在SELECT中被采用,然后在事务完成后才被释放。 这就是系统如何保证您读取的值在交易期间不会改变(因为它们保持locking直到交易完成)。

根据我对这个线程的阅读和理解,以及@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不能在表中读取或写入。 表级块
  • 快照 :每个进程都有自己的副本,他们正在处理它。 每个人都有自己的看法

我对最初接受的解决scheme的观察

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