Хороший хорошо изложенный сценарий. Я решил проверить это.
Вот мой сценарий установки:
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
Я загрузил этот тестовый скрипт в два окна анализатора запросов и запустил каждую часть, как описано в вопросе.
Все чтение происходит перед любой записью, поэтому все потоки / сценарии будут читать значение 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 , оба не блокируют данные, которые были прочитаны от изменений другими пользователями. Разница в том, что чтение без подтверждения позволит вам увидеть данные, которые еще не зафиксированы (недостаток), и не заблокирует чтение, если есть данные, заблокированные другими пользователями для чтения (вверх), что на самом деле говорит одно и то же дважды.
Повторяемое чтение и Сериализуемый , оба ведут себя как чтение, зафиксированное для чтения. Для блокировки оба блокируют данные, которые были прочитаны против модификации другими пользователями. Разница в том, что сериализуемые блоки больше, чем строка, которая была прочитана, а также блокирует вставки, которые вводят записи, которых раньше не было.
Таким образом, при повторяемом чтении вы можете увидеть новые записи (называемые фантомными записями) в последующих чтениях. С сериализуемым, вы блокируете создание этих записей, пока не сделаете коммит.
Приведенные выше объяснения получены из моей интерпретации этой msdn статьи.