以下はからの引用です 70-762 Developing SQL Databases (p. 212)
:
2つのプロセスが同じ行を読み取り、そのデータを異なる値で更新すると、別の潜在的な問題が発生する可能性があります。これは、トランザクションが最初に値を変数に読み込み、その後のステップで更新ステートメントでその変数を使用する場合に発生する可能性があります。この更新が実行されると、別のトランザクションが同じデータを更新します。これらのトランザクションのいずれかが最初にコミットされると、他のトランザクションの更新に置き換えられたため、更新が失われます。分離レベルを使用してこの動作を変更することはできませんが、失われた更新を特に許可するアプリケーションを作成することはできます。
したがって、このような場合、どの分離レベルも役に立たないようであり、コード自体で問題を解決する必要があります。例えば:
DROP TABLE IF EXISTS [dbo].[Balance];
CREATE TABLE [dbo].[Balance]
(
[BalanceID] TINYINT IDENTITY(1,1)
,[Balance] MONEY
,CONSTRAINT [PK_Balance] PRIMARY KEY
(
[BalanceID]
)
);
INSERT INTO [dbo].[Balance] ([Balance])
VALUES (100);
-- query window 1
BEGIN TRANSACTION;
DECLARE @CurrentBalance MONEY;
SELECT @CurrentBalance = [Balance]
FROM [dbo].[Balance]
WHERE [BalanceID] = 1;
WAITFOR DELAY '00:00:05'
UPDATE [dbo].[Balance]
SET [Balance] = @CurrentBalance + 20
WHERE [BalanceID] = 1;
COMMIT TRANSACTION;
-- query window 2
BEGIN TRANSACTION;
DECLARE @CurrentBalance MONEY;
SELECT @CurrentBalance = [Balance]
FROM [dbo].[Balance]
WHERE [BalanceID] = 1;
UPDATE [dbo].[Balance]
SET [Balance] = @CurrentBalance + 50
WHERE [BalanceID] = 1;
COMMIT TRANSACTION;
テーブルを作成し、コードの各部分を個別のクエリウィンドウで実行します。分離レベルを変更しても何も起こりません。たとえば、との唯一の違いread committed
はrepeatable read
、最後のトランザクションが最初のトランザクションの終了時に2番目のトランザクションをブロックし、値を上書きすることです。