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


当前回答

可重复读取

数据库的状态从事务开始时开始维护。如果在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

有道理吗?

其他回答

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

有两个事务A和B。 事务B正在读取表X 事务A正在写表X 事务B在表X中再次读取数据。

ReadUncommitted: Transaction B can read uncommitted data from Transaction A and it could see different rows based on B writing. No lock at all ReadCommitted: Transaction B can read ONLY committed data from Transaction A and it could see different rows based on COMMITTED only B writing. could we call it Simple Lock? RepeatableRead: Transaction B will read the same data (rows) whatever Transaction A is doing. But Transaction A can change other rows. Rows level Block Serialisable: Transaction B will read the same rows as before and Transaction A cannot read or write in the table. Table-level Block Snapshot: every Transaction has its own copy and they are working on it. Each one has its own view

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

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

下一个隔离级别是可序列化的,它提供了更强的保证:除了所有可重复读取的保证之外,它还保证后续读取不能看到任何新数据。

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

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

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

under READ COMMITTED, the second SELECT may return any data. A concurrent transaction may update the record, delete it, insert new records. The second select will always see the new data. under REPEATABLE READ the second SELECT is guaranteed to display at least the rows that were returned from the first SELECT unchanged. New rows may be added by a concurrent transaction in that one minute, but the existing rows cannot be deleted nor changed. under SERIALIZABLE reads the second select is guaranteed to see exactly the same rows as the first. No row can change, nor deleted, nor new rows could be inserted by a concurrent transaction.

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

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

补充阅读:

数据库引擎中的隔离级别 并发性的影响 选择基于行版本的隔离级别

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

可重复读取

数据库的状态从事务开始时开始维护。如果在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

有道理吗?

我对初始接受解的观察。

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