1

对于同一个 ADO.Net 语句,我想确保我对隔离级别和锁的理解是正确的。

  1. 在默认 SQL Server 隔离级别(已提交读)下,读取每一行后,该行将解锁;

  2. 如果我将隔离级别提高到可重复读取,锁(在整个表上?还是其他级别的锁?)将一直保持到 while 循环结束?

例如:

SqlCommand cmd = conn.CreateCommand();

cmd.CommandText= "select operation_id, operation_code, product_id, quantity
from dbo.operations where processed=0";

reader=cmd.ExecuteReader();

while (reader.Read())    
{
   // some operations
}

提前谢谢,乔治

4

3 回答 3

1

一些关于隔离级别差异的有用文章:READ COMMITTED 和 REPEATABLE READ 下的选择可能会返回不正确的结果。

快照隔离何时有帮助,何时有害

于 2009-07-11T18:00:59.927 回答
1

1)您的第一点不正确:Read Committed的默认隔离级别意味着不会发生Dirty Reads(尽管可能会发生幻读或不可重复读取)。它不保证单行被锁定。

在以下情况下可能会发生不可重复读取:

1. Transaction 1 begins
2. Transaction 1 read a row
3. Transaction 2 begins
4. Transaction 2 changes the value of the same row read by Transaction 1
5. Transaction 2 commits
6. Transaction 1 reads the row again. Transaction 1 has inconsistent data.

2)Repeatable Read隔离级别意味着上述情况不会发生(尽管幻读仍然可能)。在以下情况下可能会发生幻读:

1. Transaction 1 begins
2. Transaction 1 read a row
3. Transaction 2 begins
4. Transaction 2 deletes the row read by Transaction 1
5. Transaction 2 commits. Transaction 1 can no longer repeat its initial read, 
   since the row no longer exists.

如果您想保证数据在读取时不会更改,则需要 Serializable 隔离级别。我强烈建议不要使用 Serializable 隔离级别,除非你绝对必须这样做,因为并发性会受到影响。

于 2009-07-11T16:48:16.127 回答
1

在可重复读取或可序列化隔离级别中,SELECT 获取的行锁将一直保持到事务提交,而不是直到循环结束。如果您未指定显式事务,则 SELECT 语句将启动一个隐式事务,该事务将在 SELECT 语句完成时自动提交。这与 while 循环结束的时刻不同,循环在客户端上,并且 SELECT 语句可能在循环结束之前在服务器上完成。

正如米奇所说,更高级别的隔离级别有一定的目的,以避免幻读或不可重复读。在自动提交的隐式事务中,单个 SELECT 语句不能要求更高的隔离级别。当数据被多次读取时,这些级别仅在多个语句事务中起作用。如果您解释您正在执行的操作的上下文以及您为什么担心此 SELECT 将放置的锁,也许会更好?

于 2009-07-11T18:33:12.377 回答