我正在尝试解决我的应用程序中的竞争条件。
我有一个用作工作队列和许多线程并读取/更新它的表。以下查询从应用程序执行。首先,它读取可用作业的 ID,然后保留它们并获取信息。
SELECT ID FROM JOBS WHERE LOCKED_BY IS NULL LIMIT 5; --Check available jobs
UPDATE JOBS LOCKED_BY = 'Thread#1' WHERE ID IN (?); --Lock jobs
SELECT * FROM JOBS WHERE ID IN(?); --Get info about jobs to process
当多个线程同时进入此表时会出现问题。如果'Thread#2'
在'Thread#1'
运行UPDATE
. 导致相同的作业运行两次。
我通过将查询包装在以下内容中找到了解决方案:
LOCK TABLE JOBS;
--Queries from above
COMIT;
这可以正常工作并防止竞争条件,但它有点极端,因为线程必须等待彼此完成。
如何确保只能对来自以下查询的记录进行锁定?
SELECT ID FROM JOBS WHERE LOCKED_BY IS NULL LIMIT 5;
这是在 AS400 DB2 数据库上,现在是 LUW
你为什么用桌子?IBM i 提供了一个本地数据队列对象...
如果您的应用程序以不提供对本机对象的直接访问的语言在平台外运行,您总是可以在 I 上构建存储过程或用户定义的函数来提供对数据队列的访问。
话虽如此,对于任何 RDBMS,您的问题的答案都是相同的,请使用隔离级别。
在您的情况下,您想使用Read Stability
只需添加
WITH RS
到您的陈述...第一条语句将锁定(最多)5 行..直到
COMMIT
完成。请注意,如果还没有记录该表,则需要记录该表。
作为锁定的替代方案(使用 RS 隔离运行仍然会有线程相互等待并可能死锁,除非你
SELECT .. FOR UPDATE
),如果你可以容忍一次处理少于 5 个作业,你可以使用乐观的方法: