我正在尝试使用以下MySQL表实现锁定机制:
CREATE TABLE Locker (
`Id` int(11),
`locked_until` timestamp null,
unique index `unique` (`Id` asc)
);
我们的想法是会有多个进程接收id
来处理。处理本身发生在MySQL之外,但我想使用数据库表来跟踪当前正在进行的处理,并禁止同时处理相同的id
。
我的想法如下:
id
我将在表格中插入(或更新)相应的记录,将locked_until
设置为合理的值(通常为“CURRENT TIMESTAMP + INTERVAL 30 SECOND”)UPDATE Locker SET locked_until=null WHERE id={current_id}
我在列表中的第一个项目符号遇到问题,因为有三种不同的情况需要处理:
id
==>不存在行应该插入locked_until
为null
或过去的值)==>应使用新的locked_until
值我目前的状态是:
insert into Locker (Id, locked_until)
values (3, current_timestamp + interval 60 second)
on duplicate key update locked_until = current_timestamp + interval 60 second;
但问题是它忽略了当前更新的行。我无法添加WHERE
子句,因为这是无效的语法。
我也会尝试做一个conditional update,但我不确定如何向该调用程序发回该元素当前被锁定的信号。 (因为SQL Server中不支持output
)
是否可以在一个声明中完成所有这些?
我找到了一种方法,但感觉很糟糕:
insert into Locker (Id, locked_until)
values (3, current_timestamp + interval 60 second)
on duplicate key update locked_until = if(locked_until < current_timestamp,
current_timestamp + interval 60 second,
'error');
如果需要评估if
的第二部分,'error'
值会使其爆炸,表示该特定项目当前已被锁定。
我仍然在寻找更好/更清洁的方法来做到这一点。
答案 0 :(得分:1)
您可以在当前状态查询后检查受影响的行数。对于新的Id,它将为1,而对于更新的现有记录,它将返回2.如果Id存在且locked_until未更改,则受影响的行的N = 0.至少这是我在旧的mariadb实例上看到的。