うまく説明された素晴らしいシナリオ。私はそれをテストすることにしました。
これが私のセットアップスクリプトです:
CREATE TABLE Deposits(Amount Money, UserID int)
INSERT INTO Deposits (Amount, UserID)
SELECT 0.0, 123
--Reset
UPDATE Deposits
SET Amount = 0.00
WHERE UserID = 123
これが私のテストスクリプトです。
SET TRANSACTION ISOLATION LEVEL Serializable
----------------------------------------
-- Part 1
----------------------------------------
BEGIN TRANSACTION
DECLARE @amount MONEY
SET @amount =
(
SELECT Amount
FROM Deposits
WHERE UserId = 123
)
SELECT @amount as Amount
----------------------------------------
-- Part 2
----------------------------------------
DECLARE @amount MONEY
SET @amount = *value from step 1*
UPDATE Deposits
SET Amount = @amount + 100.0
WHERE UserId = 123
COMMIT
SELECT *
FROM Deposits
WHERE UserID = 123
このテスト スクリプトを 2 つのクエリ アナライザー ウィンドウにロードし、質問の説明に従って各部分を実行しました。
すべての読み取りは書き込みの前に行われるため、すべてのスレッド/シナリオは 0 の値を @amount に読み取ります。
結果は次のとおりです。
コミットされた読み取り
1 T1.@Amount = 0.00
2 T1.@Amount = 0.00
3 Deposits.Amount = 100.00
4 Deposits.Amount = 100.00
コミットされていない読み取り
1 T1.@Amount = 0.00
2 T1.@Amount = 0.00
3 Deposits.Amount = 100.00
4 Deposits.Amount = 100.00
反復可能な読み取り
1 T1.@Amount = 0.00 (locks out changes by others on Deposit.UserID = 123)
2 T1.@Amount = 0.00 (locks out changes by others on Deposit.UserID = 123)
3 Hangs until step 4. (due to lock in step 2)
4 Deadlock!
Final result: Deposits.Amount = 100.00
シリアライズ可能
1 T1.@Amount = 0.00 (locks out changes by others on Deposit)
2 T1.@Amount = 0.00 (locks out changes by others on Deposit)
3 Hangs until step 4. (due to lock in step 2)
4 Deadlock!
Final result: Deposits.Amount = 100.00
思考シミュレーションを通じてこれらの結果に到達するために使用できる各タイプの説明を次に示します。
Read CommittedとRead Uncommitedはどちらも、他のユーザーによる変更に対して読み取られたデータをロックしません。違いは、コミットされていない読み取りでは、まだコミットされていないデータを表示できること (欠点) と、読み取りに対して他のユーザーによってロックされているデータがある場合に読み取りをブロックしないことです (利点)。
Repeatable ReadとSerializableはどちらも、読み取りのためにコミットされた読み取りのように動作します。ロックの場合、両方とも、他のユーザーによる変更に対して読み取られたデータをロックします。違いは、シリアル化可能なブロックは、読み取られた行よりも多く、以前には存在しなかったレコードを導入する挿入もブロックすることです。
したがって、反復可能な読み取りを使用すると、後の読み取りで新しいレコード (ファントム レコードと呼ばれる) を確認できます。serializable を使用すると、コミットするまでこれらのレコードの作成をブロックできます。
上記の説明は、このmsdn記事の私の解釈から来ています。