以下引自 70-762 Developing SQL Databases (p. 212)
:
当两个进程读取同一行然后用不同的值更新该数据时,可能会出现另一个潜在问题。如果事务首先将值读入变量,然后在后续步骤的更新语句中使用该变量,则可能会发生这种情况。执行此更新时,另一个事务会更新相同的数据。这些事务中的任何一个首先提交都会成为丢失的更新,因为它被另一个事务中的更新替换。您不能使用隔离级别来更改此行为,但您可以编写一个专门允许丢失更新的应用程序。
因此,在这种情况下,似乎没有任何隔离级别可以帮助您,您需要在代码本身中解决问题。例如:
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
是最后一个事务在第一个事务完成时阻塞第二个事务,然后覆盖该值。