views:

1373

answers:

3

Hello everyone,

For the same ADO.Net statement, I want to make sure my understanding of isolation level and lock is correct.

  1. In default SQL Server isolation level (read committed), after read each row, the row will unlocked;

  2. If I raise isolation level to repeatable read, the lock (on the whole table? or some other level lock?) will be hold until the end of while loop?

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
}

thanks in advance, George

+1  A: 

1) Your first point is not correct: The default isolation level of Read Committed means that Dirty Reads will not occur (although phantom or non-repeatable reads might). It does not guarantee that single rows are locked.

A non-repeatable read can occur in the following situation:

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 isolation level means the above situation cannot occur (though phantom reads still might). A phantom read can occur in the following situation:

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.

If you want to guarantee that data does not chnage while you read it, you would need the Serializable isolation level. I would strongly advise agianst not using the Serializable isolation level unless you absolutely have to, as concurrency will suffer.

Mitch Wheat
Thanks Mitch, for (1), I am confused that if the row is not locked, how to guarantee not reading dirty data (if not locked, other transactions may change/delete the row)? for (2), if I raise isolation level to repeatable read, I think all the rows (which are selected by the SELECT WHERE statements) are locked in the while loop, is that correct understanding? If not locked, how to guarantee repeatable read?
George2
+1  A: 

A few useful articles about differences in isolation levels: Selects under READ COMMITTED and REPEATABLE READ may return incorrect results.

When Snapshot Isolation Helps and When It Hurts

AlexKuznetsov
Hi AlexKuznetsov, in your first link, I am confused about why in read committed isolation level, the select sum transaction will get different results. My confusion is I think select sum transaction will always read committed, so account should always be balanced -- account transfer transaction will only commit when both withdraw and deposite operations are successful. Any comments?
George2
@George2: you may get different results because a row may be counted twice or not counted at all. When you modify a row in my example, the corresponding index entry moves. Because the query scan this index, it can count the moved index entry twice.
AlexKuznetsov
+1  A: 

In repeatable read or in serializable isolation levels the row locks acquired by the SELECT will be held until the transaction commits, not until the end of the loop. If you do not specify an explicit transaction then the SELECT statement will start an implicit one that will auto-commit when the SELECT statement completes. That is not the same moment as when the while loop ends, the loop is on the client and the SELECT statement may complete on the server before your loop ends.

As Mitch said, the higher level isolation levels have a certain purpose, to avoid phantom reads or non-repeatable reads. A single SELECT statement, in an auto-committed implicit transaction, cannot require a higher isolation level. These levels only come into play on multiple statement transactions, when data is read multiple times. Perhaps is better if you explain the context of the operation you're doing and why are you concerned about the locks this SELECT will place?

Remus Rusanu
Thanks Remus, great reply! Two more comments, 1. "That is not the same moment as when the while loop ends", do you mean we hold lock just after we execute select statement? If yes, I disagree since I read the data by using DataReader in a while loop (in a streaming way), and lock should be hold until the end of loop. Appreciate if you could clarify. :-) 2. "A single SELECT statement, in an auto-committed implicit transaction, cannot require a higher isolation level." -- I am confused. I think in T-SQL, single statement transaction is allowed and in the transaction we should be able to
George2
(continued) set isolation level. Appreciate if you could clarify.
George2
1) The SELECT statement will end, and thus auto-commit, as soon as the last row is sent back to the client. The client network stack will buffer all rows received until they are consumed by the SqlDataReader. Thus you can iterate your loop long after the SELECT has already finished on the server. 2) *not require* as in *there is no point* in doing so. If you're not reading the same data *again* in the transaction, then the higher isolation levels make no sense.
Remus Rusanu