Sql-Server

失去的更新是否在 SQL Server 中完全處理,還是仍需要手動干預?

  • June 2, 2021

當 2 個不同的事務嘗試同時更新同一事物時會發生失去更新 - 不同的會話更新同一行;最後一個覆蓋第一個所做的更改。

我們可以通過 T-SQL 命令控制鎖定,但無法控制閂鎖的行為。SQL Server 是否在每種情況下都完全處理了失去更新問題,或者在某些情況下可能無法保持一致性?

如果沒有,應該怎麼做才能防止失去更新機會?

避免“失去更新”問題的一種方法是使用樂觀並發技術,其中更改被靜默覆蓋並且最後一個獲勝。這可以通過使用rowversion列並在每次更新期間比較原始值和目前值來完成。如果任何行值更改或刪除了行,則可以拒絕更新。

CREATE TABLE dbo.Customer(
   CustomerID int NOT NULL IDENTITY
       CONSTRAINT PK_Customer PRIMARY KEY
   , LastName varchar(50) NOT NULL
   , FirstName varchar(50) NOT NULL
   , EMailAddress varchar(255) NOT NULL
   , RowVersion rowversion
);
GO

CREATE PROCEDURE dbo.UpdateCustomer
     @CustomerID int
   , @LastName varchar(50)
   , @FirstName varchar(50)
   , @EMailAddress varchar(255)
   , @OriginalRowVersion rowversion
AS
SET NOCOUNT ON;
UPDATE dbo.Customer
SET 
     LastName =  @LastName
   , FirstName = @FirstName
   , EMailAddress = @EMailAddress
WHERE
   CustomerID = @CustomerID
   AND RowVersion = @OriginalRowVersion;

IF @@ROWCOUNT = 0
BEGIN
   RAISERROR ('Customer was updated or deleted by another user', 16, 1);
END;
GO

SQL Server 類似地在SNAPSHOT事務隔離級別執行樂觀並發檢查。當在SNAPSHOT會話中修改行時,數據庫引擎在內部檢查行的目前事務序列號以確定它是否在目前快照事務之外被修改,並在行已更改時引發錯誤“快照隔離事務因更新衝突而中止”或刪除。rowversion這在沒有列、值檢查和RAISERROR上面的範例中提供了相同的保護,防止失去更新。

引用自:https://dba.stackexchange.com/questions/228675