SQL 服务器锁定 Rows/Table

SQL Server Locking Rows/Table

我有一个必须执行以下操作的存储过程:

我有四个客户端,每个客户端每分钟 运行,并调用此存储过程。

每个客户端只能接收他们自己的 500 行。两个客户永远不应该得到同一行。

有时候会出现两个客户端走同一条线,我想解决这个问题。

(我的想法是将代码重写为只有一个有输出的更新语句)

对于这种情况,哪种方法最好?我需要配置隔离级别吗?

这是当前代码示例:

SET XACT_ABORT ON

BEGIN TRANSACTION

    DECLARE @IDs TABLE (ID INT) -- declaring table variable
    
    INSERT INTO @IDs    -- insert unflagged IDs (data) into table variable with update lock
        SELECT TOP 500 p.[ID]
        FROM [Core].[Poruka] p WITH (UPDLOCK)
        JOIN Core.vwKorisnickiRacunOmogucenoSlanje vk
             ON p.KorisnickiRacunSifra = vk.KorisnickiRacunSifra
        WHERE 
            (p.Zauzeto = 0 OR p.Zauzeto IS NULL)
            AND vk.OmogucenoSlanjePoruka = 1
        ORDER BY 
            vk.Prioritet

    UPDATE p -- update table to flagged
    SET Zauzeto = 1
    FROM Core.Poruka p
    JOIN @IDs tmp ON tmp.ID = p.ID

    SELECT *      -- select data to client
    FROM [Core].[Poruka] p
    WHERE p.ID IN (SELECT ID 
                   FROM @IDs)

    COMMIT

这里不需要交易。

只需使用OUTPUT将更改的行输出到客户端

UPDATE p
SET Zauzeto = 1   -- update table to flagged
OUTPUT inserted.* -- output to client
FROM (
    SELECT TOP (500)
        p.*
    FROM [Core].[Poruka] p
        JOIN Core.vwKorisnickiRacunOmogucenoSlanje vk
        ON p.KorisnickiRacunSifra = vk.KorisnickiRacunSifra
    WHERE 
        (p.Zauzeto = 0 OR p.Zauzeto IS NULL)
        AND vk.OmogucenoSlanjePoruka = 1
    ORDER BY 
        vk.Prioritet
) p;

您确实应该将此联接作为 EXISTS,以避免从联接返回重复的行。

UPDATE p
SET Zauzeto = 1   -- update table to flagged
OUTPUT inserted.* -- output to client
FROM (
    SELECT TOP (500)
        p.*
    FROM [Core].[Poruka] p
    WHERE 
        (p.Zauzeto = 0 OR p.Zauzeto IS NULL)
        AND EXISTS (SELECT 1
            FROM Core.vwKorisnickiRacunOmogucenoSlanje vk
            WHERE
                p.KorisnickiRacunSifra = vk.KorisnickiRacunSifra  --join condition
                AND vk.OmogucenoSlanjePoruka = 1
        )
    ORDER BY 
        vk.Prioritet
) p;

SERIALIZABLE(又名 HOLDLOCK)隔离级别在这里是明智的。