許多開發者誤以為 TIMESTAMP 是日期時間型別,實際上它是資料庫級遞增的二進位版本號(SQL Server 2012+ 建議用 ROWVERSION 同義字)。本文深入解析其運作原理、並發控制模式與增量同步應用。
ROWVERSION 資料表的 INSERT/UPDATE,計數器遞增並寫入該欄。ROWVERSION 欄位。SELECT @@DBTS 回傳目前資料庫最大 timestamp。場景:使用者 A、B 同時編輯同一筆資料,最後存檔者不應覆蓋先前變更。
CREATE TABLE dbo.Account (
Id INT PRIMARY KEY,
Balance DECIMAL(18,2),
Ver ROWVERSION -- 或 TIMESTAMP
);
-- 1. 讀取時同時取得 Ver
DECLARE @ver ROWVERSION;
SELECT @ver = Ver, Balance = 1000 FROM Account WHERE Id = 1;
-- 2. 業務邏輯運算...
-- 3. 更新時帶入原 Ver 做 WHERE 條件
UPDATE Account
SET Balance = 900
WHERE Id = 1 AND Ver = @ver; -- 若 Ver 已被他人改變,ROWCOUNT = 0
IF @@ROWCOUNT = 0
THROW 50001, '資料已被他人修改,請重新整理', 1;
需求:每小時將主庫異動同步至報表庫,不想用完整 CDC/Replication。
-- 1. 記錄上次同步最大 timestamp
CREATE TABLE SyncWatermark (TableName SYSNAME PRIMARY KEY, LastTs BINARY(8));
INSERT INTO SyncWatermark VALUES ('Account', 0x00000000000007D0);
-- 2. 同步查詢(只抓變更列)
DECLARE @last BINARY(8) = (SELECT LastTs FROM SyncWatermark WHERE TableName = 'Account');
SELECT Id, Balance, Ver
FROM Account
WHERE Ver > @last; -- 二進位直接比較
-- 3. 同步完成後更新 watermark
UPDATE SyncWatermark
SET LastTs = (SELECT MAX(Ver) FROM Account)
WHERE TableName = 'Account';
-- 建立測試表
CREATE TABLE #Tmp (Val VARCHAR(10), Ver ROWVERSION);
INSERT INTO #Tmp (Val) VALUES ('abc');
-- 連線 1 (SSMS 視窗 1)
BEGIN TRAN;
DECLARE @rv ROWVERSION;
SELECT @rv = Ver FROM #Tmp WHERE Val = 'abc';
WAITFOR DELAY '00:00:05'; -- 模擬思考時間
UPDATE #Tmp SET Val = 'xyz' WHERE Ver = @rv;
COMMIT;
-- 連線 2 (SSMS 視窗 2,在 5 秒內執行)
DECLARE @rv ROWVERSION;
SELECT @rv = Ver FROM #Tmp WHERE Val = 'abc';
UPDATE #Tmp SET Val = 'aaa' WHERE Ver = @rv; -- 此時 Ver 已被連線 1 更新,ROWCOUNT = 0
連線 2 更新失敗,成功避免「遺失更新」。
ROWVERSION 關鍵字,語意更清晰。TIMESTAMP 可就地保留,功能完全相容。DATETIME2 欄位搭配 DEFAULT SYSUTCDATETIME() + 觸發器更新。掌握 ROWVERSION,即可輕鬆實現高效能樂觀鎖與輕量級增量同步,是分散式系統與高併發應用的基石工具。