对于相同的ADO.Net声明,我想确保我对隔离级别和锁定的理解是正确的。
在默认的SQL Server隔离级别(读取已提交)中,读取每一行后,该行将解锁;
如果我将隔离级别提升到可重复读取,则锁定(在整个表上?或其他一些级别锁定?)将保持到while循环结束?
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
}
提前谢谢,
乔治
答案 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将要放置的锁?