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

SQL Server 全域暫存表防重複登入實戰:連線斷開自動清理機制

     編輯:關於SqlServer

業務痛點

商務系統需限制同一帳號同時在線。資料表旗標法:登入寫 1、登出寫 0。但異常斷電、瀏覽器關閉、Process Kill 導致旗標殘留 1,用戶無法再次登入,需管理員手動重置。

核心洞察:全域暫存表生命週期綁定工作階段

  • ##GlobalTemp 於最後一個參考工作階段結束時自動刪除
  • 正常登出 → 連線關閉 → 工作階段結束 → 表自動消失
  • 異常斷電 → 連線中斷 → 工作階段結束 → 表自動消失
  • 殘留在 tempdb 中但無活動工作階段引用 → OBJECT_ID() 判定為不存在

完整實作

檢查並建立儲存程序

CREATE PROCEDURE dbo.CheckUserLogin
    @UserID VARCHAR(20),
    @IsLoggedIn BIT OUTPUT
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @TableName NVARCHAR(100) = N'##Login_' + @UserID
    DECLARE @SQL NVARCHAR(MAX)

    -- OBJECT_ID 判斷:無活動工作階段引用時回傳 NULL
    IF OBJECT_ID('tempdb..' + @TableName) IS NULL
    BEGIN
        -- 動態建表:避免編譯期解析錯誤
        SET @SQL = N'CREATE TABLE ' + @TableName + N' (UserID VARCHAR(20) PRIMARY KEY)'
        EXEC sp_executesql @SQL
        
        -- 記錄登入資訊(可擴充:登入時間、IP、SessionID)
        EXEC sp_executesql N'INSERT ' + @TableName + N' VALUES (@uid)', 
            N'@uid VARCHAR(20)', @UserID
        
        SET @IsLoggedIn = 0  -- 允許登入
    END
    ELSE
    BEGIN
        SET @IsLoggedIn = 1  -- 已在線,拒絕
    END
END

應用層呼叫

// C# 範例
bool isLoggedIn;
using (var cmd = new SqlCommand("dbo.CheckUserLogin", conn) { CommandType = CommandType.StoredProcedure })
{
    cmd.Parameters.AddWithValue("@UserID", userId);
    var outParam = cmd.Parameters.Add("@IsLoggedIn", SqlDbType.Bit);
    outParam.Direction = ParameterDirection.Output;
    cmd.ExecuteNonQuery();
    isLoggedIn = (bool)outParam.Value;
}

if (isLoggedIn)
    throw new Exception("此帳號已在其他地方登入,請先登出。");

登出時主動清理(可選,加速釋放)

CREATE PROCEDURE dbo.ReleaseUserLogin @UserID VARCHAR(20)
AS
BEGIN
    DECLARE @TableName NVARCHAR(100) = N'##Login_' + @UserID
    IF OBJECT_ID('tempdb..' + @TableName) IS NOT NULL
        EXEC(N'DROP TABLE ' + @TableName)
END

進階擴充:多裝置、Session 資訊記錄

CREATE TABLE ##Login_ (
    UserID VARCHAR(20),
    SessionID VARCHAR(50),      -- 應用層產生的 Session ID
    LoginTime DATETIME DEFAULT GETDATE(),
    ClientIP VARCHAR(45),
    UserAgent VARCHAR(500),
    PRIMARY KEY (UserID, SessionID)
)

-- 允許同一用戶多裝置:檢查 SessionID 是否存在
-- 強制踢人:管理員刪除對應 SessionID 列

優缺點分析

分散式/雲端環境替代方案

  • Redis 分散式鎖:SET user:lock:{uid} {sessionId} NX EX 86400
  • 資料表旗標 + 背景作業:定期掃描超時未心跳的旗標重置
  • SignalR / WebSocket 心跳:即時偵測連線狀態

注意事項

  • 全域暫存表名稱長度 ≤ 116 字元(含 ##)
  • 避免在觸發器中建立全域暫存表(巢狀交易複雜)
  • 監控 tempdb.sys.tables WHERE name LIKE '##Login_%' 數量
  • SQL Server 重啟會清空所有暫存表,服務重啟後用戶需重新登入(可接受)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
優點缺點/限制
零資料表旗標維護僅適用單一 SQL Server 實例
異常斷線自動恢復Always On 可用性群組次要複本不可寫入暫存表
無需排程清理殘留旗標大量併發登入可能產生大量全域暫存表
實作簡單、效能極佳tempdb 壓力大時需監控