mysql - 使用数据库实现的锁定机制
问题描述
我正在尝试使用以下 MySQL 表实现锁定机制:
CREATE TABLE Locker (
`Id` int(11),
`locked_until` timestamp null,
unique index `unique` (`Id` asc)
);
这个想法是会有多个进程接收id
s 来处理。处理本身发生在 MySQL 之外,但我想使用数据库表来跟踪当前正在进行的处理,并禁止同时id
处理相同的处理。
我的想法如下:
- 给定
id
我将在表中插入(或更新)相应记录,设置locked_until
为合理的值(通常为 `CURRENT TIMESTAMP + INTERVAL 30 SECOND) - 在 MySQL 之外进行处理
- 处理项目时,
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
子句,因为这是无效的语法。
我也会尝试进行有条件的更新,但我不确定如何向调用程序发回该元素当前已锁定的信号。(因为output
在 SQL Server 中不支持)
是否可以在一个语句中完成所有这些操作?
更新:
我找到了一种方法,但感觉很hack-ish:
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'
值使其爆炸,表明该特定项目当前已被锁定。
我仍在寻找更好/更清洁的方法来做到这一点。
解决方案
您可以在当前状态查询之后检查受影响的行数。对于新的 Id,它将为 1,而对于更新的现有记录,它将返回 2。如果 Id 存在并且locked_until 未更改,则受影响的行数 = 0。至少这是我在旧的 mariadb 实例上看到的。
推荐阅读
- c# - 在最后两个标签 git 之间导出文件
- sql - SQL - 将 4 列合并为一个新列作为单个 JSON 对象
- reactjs - AWS cognito sso 用户身份验证与 django rest 框架、react js 和 ALB
- android - 清单合并失败:问题解决没有奏效
- java - 任务:app:kaptDebugKotlin FAILED(错误:找不到符号) - Kotlin
- mysql - 将 Codeigniter 项目上传到 Cpanel subdmoin 会导致 DNS_Probe_Error
- laravel - 如何在laravel中使用代码索引特定数据库的表列
- javascript - 功能顺序是否有保证?
- ssl - 如何完全删除使用 openssl 创建的自签名证书
- apache-nifi - Nifi 无法建立与服务器的连接