sql - 在 SQL Server 中,如何防止多线程应用程序读取同一行两次?
问题描述
我有一组触发器,它们在更新或删除时在单独的事件表中创建一个条目。此表包含 ID、表名和已更改/删除的数据。
我有一个多线程应用程序 .NET core 3.0 应用程序,它定期选择 ID 最低的记录,处理数据将处理后的数据发送到 API。一旦完成,它就会从表中删除该行。
问题是,如果 SELECT 由进程 1 完成,然后进程 2 在进程 1 完成 DELETE 之前完成 SELECT,则同一行可能会被不同的进程读取两次。
由于事件表没有“锁定”列,我希望通过某种行锁定和 WITH (readpast) 来完成此操作。但是,由于 SELECT 和 DELETE 在单独的事务中,我不确定这是否合适。
鉴于当前的设置,关于如何实现这一点的任何建议,或者引入锁定列是理想的方式?
解决方案
我认为,大卫建议的另一种更安全的方法是分割你的队列。
对于双进程系统,您可以将队列划分为奇数项和偶数项(基于 ID),并让一个进程处理偶数项,另一个进程处理奇数项。
这是你永远不会在两个进程之间出现死锁/竞争情况。
例子:
DECLARE @ProcessID INT = 0 -- 0 for "Process 1" and 1 for "Process 2"
SELECT TOP 1 * FROM [Queue]
WHERE ID % 2 = @ProcessID -- 2 is the number of processes
ORDER BY ID ASC
从上面可以看出,这可以扩展到任意数量的进程。
优点
- 完全避免死锁和竞争条件。
- 不需要原子操作。
缺点
- 不保证处理顺序。
- 如果一个进程停止,那么一半的项目将不会被处理。
推荐阅读
- python - 安装后没有名为“tensorflow_examples”的模块
- reactjs - 在 shopify next js 应用程序中重新加载页面而不是路由
- angular - NgbModal 上的 ComponentInstace 未定义
- mysql - 如何显示记录数
- python - 如何在 XPath 中处理更改的 ID?例如 :
- php - Node js无法通过php从curl请求中读取数据
- mysql - 为什么在使用 go lang 执行 mysql DB 操作时,内部将 sql 转换为准备好的语句样式执行
- vb.net - 如何过滤包含列数据库中指定的所有单词的记录
- python - 如何利用字典计算数据框中的多个平均值
- javascript - 使用 switch case 和过滤/查找/循环对象数组来过滤并找到正确的对象以更新 JavaScript