Consider that I have a transaction:
BEGIN TRANSACTION DECLARE MONEY @amount SELECT Amount AS @amount FROM Deposits WHERE UserId = 123 UPDATE Deposits SET Amount = @amount + 100.0 WHERE UserId = 123 COMMIT
And it gets executed on 2 threads, in the order:
- thread 1 – select
- thread 2 – select
- thread 1 – update
- thread 2 – update
Assume that before execution Amount is 0.
What will happen in this case in the different settings of SQL Server (read uncommited, read commited, repeatable read, serializable), what will be amount at the end, will there be a deadlock?
Nice well stated scenario. I decided to test it.
Here’s my setup script:
Here’s my test script.
I loaded up this test script in two query analyzer windows and ran each part as described by the question.
All of the reading happens before any of the writing, so all threads/scenarios will read the value of 0 into @amount.
Here are the results:
Read committed
Read uncommitted
Repeatable Read
Serializable
Here’s an explanation of each type which can be used to reach these results through thought simulations.
Read Committed and Read Uncommited, both do not lock the data that was read against modifications by other users. The difference is that read uncommitted will allow you to see data that is not yet committed (downside) and will not block your read if there is data locked by others against reading (upside), which is really saying the same thing twice.
Repeatable Read and Serializable, both behave like read committed for reading. For locking, both lock data which has been read against modification by other users. The difference is that serializable blocks more than the row which has been read, it also blocks inserts that would introduce records that were not present before.
So with repeatable read, you could see new records (termed : phantom records) in later reads. With serializable, you block the creation of those records until you commit.
The above explanations come from my interpretation of this msdn article.