我有一个处理传入消息的应用程序,但根据消息的类型,我希望以单例方法处理它们,这意味着不允许同时处理两个相同类型的消息.

所以在我的数据库中,我有一个包含消息的MessageInformation表和一个ExecuteStatus.其中,0=未处理,1=正在处理,6=打开.

现在,我想知道到达的新消息是应该标记为正在处理还是应该被搁置.

我使用下面的SQL语句很容易做到这一点:

IF EXISTS (SELECT 1 FROM [dbo].[MessageInformations] WHERE MessageType = @MessageType AND ExecuteStatus IN (1,6))
BEGIN
    UPDATE [dbo].[MessageInformations]
    SET ExecuteStatus = 6
    OUTPUT Inserted.ExecuteStatus
    WHERE [Identifier] = @MessageIdentifier
END
ELSE
BEGIN
    UPDATE [dbo].[MessageInformations]
    SET ExecuteStatus = 1
    OUTPUT Inserted.ExecuteStatus
    WHERE [Identifier] = @MessageIdentifier
END

这里的问题是它不是"线程安全的",这意味着如果两个消息同时到达,这两个消息可能都被标记为Processing,而实际上应该只有1个.我可以将它放在一个事务中并锁定MessageInformation表,但我不想在整个表上加锁,因为可能有其他类型的消息不想等待锁定完成,我只对该特定消息类型的消息运行此查询.其他消息类型将简单地设置为Processing.

而且表中也有很多消息,它将稳定在4,000-5,000万条左右(清除旧消息).

因此,我需要一个单独的UPDATE语句来为我完成这项工作,或者需要一种方法来仅锁定表中与MessageType匹配的行(我可以在此基础上添加一个日期范围以减少要匹配的记录,因为如果一条消息在ON Hold上超过几个小时,则一定有问题).

说得更清楚一点.以下是包括的几个步骤.

  • 首先,有一个步骤在数据库中创建消息,并将其标记为"未处理"

  • 然后,有几个处理器会获得一个分配给它们的消息标识符来try 处理这些消息.因此,基本上处理器带有一个消息标识符并需要验证是否可以处理该消息,或者是否应该将其搁置.如果它被标记为‘正在处理’=1,则处理器可以继续处理该消息,但如果它被标记为‘OnHold’=6,则处理器必须停止并结束处理.这就是我希望我的SQL查询得出的结果.

  • 当处理器处理完"Singleton"消息时,它会将其标记为"已处理"=2,并将告诉"Manager"可以获取第一个(基于创建时间)‘onhold’消息并处理它,因此它将继续,直到不再有‘onhold’消息.

  • 当数据库中存在此消息类型的"保留"或"处理"消息时到达的任何新消息都应始终进入"保留"状态,因此保留消息将按其到达的顺序进行处理.

我可以创建一个单独的表并将等待消息放在其中,但如果我可以通过简单地更改MessageInformation表中的状态来解决它,就会容易得多,因为有许多其他逻辑依赖于该表.

推荐答案

为了确保不同时处理相同类型的消息并避免锁定整个表,可以将UPDLOCK提示与公用表表达式(CTE)一起使用.

;WITH CTE AS (
    SELECT TOP 1 [Identifier], ExecuteStatus
    FROM [dbo].[MessageInformations] WITH (UPDLOCK, ROWLOCK)
    WHERE MessageType = @MessageType
    AND ExecuteStatus IN (0, 6) -- NotProcessed or OnHold
    ORDER BY <your_ordering_column> -- Specify an appropriate column for ordering
)
UPDATE CTE
SET ExecuteStatus = 1
OUTPUT Inserted.ExecuteStatus
WHERE [Identifier] = @MessageIdentifier;

Sql相关问答推荐

SQL查询视图与连接?

提高写密集型表的查询性能

如何在SQL Server中拆分包含字符和数字的列?

按分隔符和总和分析字符串

从包含PostgreSQL中的JSON值的列中提取列表或目录

Oracle分层查询-两条路径在末尾合并为一条

从结果SQL查询中排除空值

在 Postgres 中将结果按几十年划分

将具有嵌套 XML 的列转换为 SQL 中的表格格式?

通过ID和数据找到每个不同的值

如何将 START 和 END 日期之间的日期差异作为 SQL 中的单独列获取

获取上个月和上一年的值

Postgres存在限制问题「小值」

如何按日期和位置对最近 3 个报告日期的 SQL 查询结果进行透视?

如何 Select 一列具有最小值而另一列具有给定值的记录?

SQLite 中的过滤运行总和视图

基于源表的 SQL INSERT、UPDATE 和 DELETE

使用 SQL 表中的连接列删除重复记录

Oracle SQL 查询自行运行,但在包装到select count(*) from ()时失败

Amazon Redshift - 子计划的哈希表不存在