首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 利用資料表模擬自訂遞增序號:替代 IDENTITY 的並發安全實作

     編輯:關於SqlServer

需求背景

特定業務需求(如跨資料庫唯一編號、自訂起始值/步長、外部系統同步)導致無法直接使用 IDENTITY(100,1) 或 SEQUENCE(SQL 2012+)。本文示範以資料表儲存計數器,配合預存程序實現執行緒安全的遞增取號。

核心物件

-- 計數器儲存表
CREATE TABLE dbo.Common_Info (
    Name  VARCHAR(20) PRIMARY KEY,
    Value INT NOT NULL
);
INSERT INTO dbo.Common_Info (Name, Value) VALUES ('Msg_Count', 100);

並發安全預存程序

CREATE PROCEDURE dbo.GetNextMsgCount
    @NextValue INT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @Current INT;

    -- 1. 取得目前值(加 UPDLOCK, HOLDLOCK 防止幻讀與更新遺失)
    SELECT @Current = Value
    FROM dbo.Common_Info WITH (UPDLOCK, HOLDLOCK)
    WHERE Name = 'Msg_Count';

    -- 2. 嘗試原子性更新:預期值仍為 @Current 才更新
    UPDATE dbo.Common_Info
    SET Value = @Current + 1
    WHERE Name = 'Msg_Count' AND Value = @Current;

    -- 3. 判斷更新是否成功
    IF @@ROWCOUNT = 0
    BEGIN
        -- 並發衝突,重試或回傳錯誤
        RETURN -1000;  -- 自訂錯誤碼
    END

    -- 4. 回傳新序號
    SET @NextValue = @Current + 1;
    RETURN 0;
END

關鍵並發控制解析

技術作用
UPDLOCK讀取時加更新鎖,防止其他交易同時讀取相同資料列導致更新遺失
HOLDLOCK (相當於 SERIALIZABLE)維持鎖定至交易結束,防止幻讀
WHERE Value = @Current樂觀並發檢查:若值已被其他交易修改,更新影響 0 列,觸發重試
@@ROWCOUNT檢查更新是否成功

應用程式端呼叫模式(重試邏輯)

int maxRetry = 3;
int nextVal = -1;
for (int i = 0; i < maxRetry; i++) {
    int ret = execGetNextMsgCount(out nextVal); // 呼叫預存程序
    if (ret == 0) break;        // 成功
    if (ret == -1000) continue; // 並發衝突,重試
    throw new Exception("DB Error: " + ret);
}

現代替代方案比較

方案適用版本優點缺點
資料表計數器 + 預存程序所有版本完全可控、支援複雜業務邏輯需自行處理並發、效能較低
IDENTITY所有版本原生高效能、無縫隙(重啟可能跳號)無法自訂步長/起始值、難跨表/跨庫唯一
SEQUENCESQL 2012+獨立物件、可跨表共用、支援 CYCLE/CACHE需較新版本、預設緩存可能導致跳號
NEWSEQUENTIALID() / UNIQUEIDENTIFIER所有版本全域唯一、無協調成本非人類可讀、索引碎片化、儲存空間大

最佳實務建議

  1. SQL 2012+ 優先使用 SEQUENCE,設定 CACHE 1000 平衡效能與跳號風險。
  2. 舊版本或需複雜業務邏輯(如依業務類型分段編號)才採用資料表計數器。
  3. 資料表計數器務必加上 UPDLOCK, HOLDLOCK 或採用 sp_getapplock 應用程式鎖保護關鍵區段。
  4. 避免在高併發核心路徑使用單點計數器,考慮號段預分配(批次取 1000 號一次)降低資料庫壓力。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved