mysql - 跳过 mysql 更新中锁定的行以避免锁定超时

标签 mysql ruby-on-rails locking innodb

我的问题类似于: Ignoring locked row in a MySQL query 只是我已经实现了接近已接受答案中建议的逻辑。我的问题是如何最初设置进程ID。所有服务器都运行如下查询(代码位于 ruby​​ on Rails 中,但生成的 mysql 查询是):

UPDATE (some_table) SET process_id=(some process_id) WHERE (some condition on row_1) AND process_id is null  ORDER BY (row_1) LIMIT 100

现在发生的情况是所有进程都尝试更新相同的行,它们被锁定并且等待锁定超时。我希望服务器忽略被锁定的行(因为释放锁后,process_id 将不再为空,因此这里没有必要锁定)。 我可以尝试随机化要更新的一批记录,但问题是我想根据上面的查询中的 row_1 确定更新的优先级。 所以我的问题是,mysql中有没有一种方法可以检查一条记录是否被锁定,如果是则忽略它?

最佳答案

不,没有办法忽略已经锁定的行。最好的选择是确保在很长一段时间内没有任何行被锁定。这将确保任何锁冲突的持续时间都很短。这通常意味着通过在事务中锁定行(使用 FOR UPDATE)并更新行以将其标记为“锁定”来“建议”锁定行。

例如,首先您希望在不锁定任何内容的情况下找到候选行:

SELECT id FROM t WHERE lock_expires IS NULL AND lock_holder IS NULL <some other conditions>;

现在锁定您想要的行,非常快:

START TRANSACTION;
SELECT * FROM t WHERE id = <id> AND lock_expires IS NULL AND lock_holder IS NULL;
UPDATE t SET lock_expires = <some time>, lock_holder = <me> WHERE id = <id>;
COMMIT;

(技术说明:如果您计划锁定多行,请始终按特定顺序锁定它们。按主键升序排列是一个不错的选择。乱序或随机顺序锁定将使您的程序陷入死锁来自竞争进程。)

现在,您可以根据需要(少于lock_expires)来处理您的行,而不会阻塞任何其他进程(它们在非锁定选择期间不会匹配该行) ,所以总是会忽略它)。处理该行后,您可以通过idUPDATEDELETE它,也不会阻塞任何内容。

关于mysql - 跳过 mysql 更新中锁定的行以避免锁定超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15456761/

相关文章:

ruby-on-rails - 从架构中删除时间戳记字段

ruby-on-rails - ActionController::UnknownFormat in Devise::SessionsController#rails 4 中的新功能

mysql - Django MySQL 'utf8' 目前是字符集UTF8MB3的别名,将被UTF8MB4取代

mysql - 如何使用mysql在距离搜索中将表与内连接联合起来

javascript - 我如何使用 javascript 变量在网站中输入文本?

mysql - 未知的内部查询错误

ruby-on-rails - ruby on rails 中的 Payflow 支付集成

java - tryLock 方法调用是否进入 try block ?

c++ - 与 std::mutex 相比,其他互斥包装器库有哪些优势?

multithreading - 锁定 HttpRuntime.Cache 以进行延迟加载