我正在使用mariadb。有一个resource表,其中包含列id,一个used标志和其他资源描述符。每一行代表一个资源分配单位。我在分配行时遇到麻烦。

在每笔交易中,我要:


选择并锁定非used的行。
used设置为true
根据所选的行来操作数据库。
然后提交。


要求:


可以有许多并发事务。
它可以选择不是used的任何一行。
它不应该阻止。
如果第3步失败,则事务将回滚并重新启动。最好选择其他行。


首先,我尝试了SELECT * FROM resource WHERE used=0 LIMIT 1 FOR UPDATE,但在并发情况下,第二个事务将阻塞,直到第一个事务结束。

START TRANSACTION
SELECT * FROM resource WHERE used=0 LIMIT 1 FOR UPDATE    <-- second tx waits here until first commits
...
COMMIT


然后,我尝试通过ORDER BY rand()添加随机性。但这似乎将首先对整个表进行排序,因此仍然会阻塞。

START TRANSACTION
SELECT * FROM resource WHERE used=0 ORDER BY rand() LIMIT 1 FOR UPDATE    <-- still blocks
...
COMMIT


有什么提示吗?

最佳答案

我假设您的处理将花费很短的时间,或者您有大量的并发事务-否则,接受阻塞可能会更容易。

过去,我通过具有“已使用”的更详细的状态来解决此问题。

用伪代码:

begin transaction
select the row to process, set status to "in progress", and mark with unique process identifier
end transaction

begin transaction
select the row with "in progress" and my unique process identifier
complete other processing logic
set row status to "used"
if error:
   rollback transaction
   set flag to "error"
else
  commit transaction


这仍然会阻塞该表,但会持续一秒钟。

我们有一个单独的工作,寻找“被遗弃的”交易(带有“错误”标志的记录,并向管理控制台报告这些记录)。

关于mysql - 使用SQL分配资源(行),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45550613/

10-10 17:53