SQL Server表隔离级别和锁定问题

时间:2009-07-11 15:23:33

标签: .net sql-server sql-server-2008 locking isolation-level

对于相同的ADO.Net声明,我想确保我对隔离级别和锁定的理解是正确的。

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

  2. 如果我将隔离级别提升到可重复读取,则锁定(在整个表上?或其他一些级别锁定?)将保持到while循环结束?

  3. e.g:

    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
    }
    
    提前谢谢, 乔治

3 个答案:

答案 0 :(得分: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)可重复读取隔离级别意味着上述情况不会发生(尽管可能仍有幻像读取)。在以下情况下可能会发生幻像读取:

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隔离级别。我强烈建议agianst不要使用Serializable隔离级别,除非你必须这样做,因为并发会受到影响。

答案 1 :(得分:1)

答案 2 :(得分:1)

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

正如Mitch所说,更高级别的隔离级别有一定的目的,以避免幻像读取或不可重复读取。在自动提交的隐式事务中,单个SELECT语句不需要更高的隔离级别。当多次读取数据时,这些级别仅在多个语句事务中发挥作用。如果你解释一下你正在进行的操作的上下文,为什么还要关注这个SELECT将要放置的锁?