SQL 表用作队列无法正常工作

问题描述 投票:0回答:1

我使用表作为队列来处理记录。我使用此查询,有时会返回相同的 ID,而这种情况永远不会发生。我已经审查了几乎所有内容,但找不到它为不同工作人员返回相同 ID 的原因。

在这种情况下,我有 8 个工作人员检索下一批要处理的数据,偶尔我会收到一条错误消息,表明该批次已被处理。我的理解是,对于运行相同查询的不同工作人员来说,查询返回的 ID 永远不应该相同。

请多指教!

BEGIN TRANSACTION
UPDATE TOP(1) 
    tblBatch WITH (ROWLOCK, UPDLOCK, READPAST)
SET 
    BatchStatusID = 2
OUTPUT 
    inserted.BatchID
FROM 
    tblBatch
WHERE 
    tblBatch.BatchID IN (
        SELECT 
            tblBatch.BatchID
        FROM 
            tblBatch 
                INNER JOIN tblBatchName ON tblBatch.BatchID = tblBatchName.BatchID
        WHERE
            (tblBatch.BatchStatusID = 1)
        GROUP BY
            tblBatch.BatchID
        HAVING 
            COUNT(tblBatchName.BatchID) >= 1 AND COUNT(tblBatchName.BatchID) <= 2147483647
    )
COMMIT

除了 UPDLOCK 和 READPAST 之外,我还添加了 ROWLOCK 并使用事务。这没有什么区别。

sql transactions queue output rowlocking
1个回答
0
投票

您的主要问题是内部子查询引用

tblBatch
also需要锁定提示
WITH (ROWLOCK, UPDLOCK, READPAST)

您还需要确保它将直接锁定在正确的行上。你需要一个索引如下

tblBatch (BatchStatusID, BatchID)

但是看起来您可能最好使用窗口函数并直接更新子查询。

此外,该连接似乎没有执行任何操作,因此您可以将其删除。

UPDATE TOP (1) 
    b
SET 
    BatchStatusID = 2
OUTPUT 
    inserted.BatchID
FROM 
    (
        SELECT 
            b.*,
            COUNT(*) OVER (PARTITION BY b.BatchID) AS Count
        FROM
            tblBatch b WITH (ROWLOCK, UPDLOCK, READPAST)
        WHERE
            b.BatchStatusID = 1
    ) b
    WHERE
        b.count BETWEEN 1 AND 2147483647;

但是无论如何这都没有意义。假设

BatchId
是主键,则计数将始终恰好是
1
。并且
COUNT
无论如何都不能为零,并且不能大于
int
值的最大值,因此计数检查是没有意义的。

所以你不妨忘记它并使用单级更新。

UPDATE TOP(1) 
    b
SET 
    BatchStatusID = 2
OUTPUT 
    inserted.BatchID
FROM
    tblBatch b WITH (ROWLOCK, UPDLOCK, READPAST)
WHERE
    tblBatch.BatchStatusID = 1;

请注意,显式事务不是必需的:无论如何,单个语句都是原子的。

© www.soinside.com 2019 - 2024. All rights reserved.