数据库轮询,防止重复回迁
Database polling, prevent duplicate fetches
我有一个系统,中央MSSQL数据库将需要完成的作业队列保存在表中。
由于处理要求不会那么高,请求频率也不会特别高(可能最多几秒钟一次),我们决定让使用队列的应用程序在需要时简单地查询数据库;此时没有消息队列服务。
通过让客户端应用程序运行存储过程来执行单个获取,该存储过程执行所涉及的查询并返回作业ID。然后,客户端应用程序通过按ID查询来获取作业信息,并将作业设置为已处理。
性能良好;我们感觉到的唯一障碍是,因为客户端应用程序必须在作业标记为已处理之前查询详细信息并执行检查,所以在极少数情况下(每几千个作业一次),两个客户端会选择同一个作业。
作为解决这个问题的一种方法,我建议让运行的初始存储过程用时间和日期"标记"它提取的记录。存储过程在查询记录时,只会提取该"标记"为过去某一时间量(例如5秒)的记录。这样,如果存储过程在5秒内运行两次,则第二个实例将不会获得相同的作业。
有人能预见到以这种方式解决问题会有什么问题吗?或者能提供一个替代解决方案吗?
使用UNIQUEIDENTIFIER
字段作为标记。当存储过程运行时,锁定正在读取的行,并使用NEWID()
更新字段。如果您担心死锁问题,可以使用WITH(READPAST)
之类的东西标记轮询语句。
在这里使用GUID的原因是有一个唯一的标识符,用于标记批次。您的NEWID()
调用保证为您提供一个唯一的值,该值将用于防止您意外地两次获取相同的数据。GETDATE()
在这里不起作用,因为最终可能会有两个调用同时解析;BIT
不起作用,因为它不会唯一地标记用于提取或报告的批次。
例如,
declare @ReadID uniqueidentifier
declare @BatchSize int = 20; -- make a parameter to your procedure
set @ReadID = NEWID();
UPDATE tbl WITH (ROWLOCK)
SET HasBeenRead = @ReadID -- your UNIQUEIDENTIFIER field
FROM (
SELECT TOP (@BatchSize) Id
FROM tbl WITH(UPDLOCK ROWLOCK READPAST )
WHERE HasBeenRead IS null ORDER BY [Id])
AS t1
WHERE ( tbl.Id = t1.Id)
SELECT Id, OtherCol, OtherCol2
FROM tbl WITH(UPDLOCK ROWLOCK READPAST )
WHERE HasBeenRead = @ReadID
然后你可以使用像这样的轮询语句
SELECT COUNT(*) FROM tbl WITH(READPAST) WHERE HasBeenRead IS NULL
改编自此处:https://msdn.microsoft.com/en-us/library/cc507804%28v=bts.10%29.aspx
- 查询SQLite数据库中的日期
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 如何在ArangoDb AQL查询中指定数据库
- 从数据库实时显示QT c++中的数据
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- 无法在C++中建立与MySQL数据库的连接
- 将类实现到数据库程序中
- 连接 dockerized 模型和 dockerized 数据库时出现"无法 SQLConnect"错误
- C++应用程序 MySQL odbc 数据库连接错误:在引发"otl_tmpl_exception<>"实例后终止调用
- 调试编译的服务器在数据库打开时崩溃
- C++变量mysql_query到数据库
- LMDB:在有限的内存系统中打开大型数据库
- 如何在多个线程中创建 QSql数据库连接时防止名称冲突
- 以只读模式打开数据库时SQLITE_CANTOPEN错误
- 如何使用SQLite将数据库中的值导出为C / C++中的字符串或字符?
- 如何在Qt中从数据库中检索二进制数据?
- 如何从网站获取数据并将其传输到数据库?
- 在装有 CLion 的 Mac 上使用 C++ 连接到 MySQL 数据库时出现问题
- Qt5 从 MySQL 数据库中选择数据
- 当我不需要数据库中的所有值时,如何部分初始化 c++ 对象?