0

我的问题类似于: 忽略 MySQL 查询中的锁定行, 除了我已经实现了一个接近于接受答案中建议的逻辑。我的问题是如何最初设置进程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中有没有办法检查记录是否被锁定并忽略它?

4

1 回答 1

1

不,没有办法忽略已经锁定的行。您最好的选择是确保在任何延长的时间段内都不会锁定任何行。这将确保任何锁定冲突的持续时间都非常短。这通常意味着通过将行锁定在事务中(使用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不阻塞任何其他进程的情况下(小于 )处理您的行(它们不会在非锁定选择期间匹配该行,因此将始终忽略它)。处理完该行后,您可以通过UPDATEDELETEid,也不会阻塞任何东西。

于 2013-03-24T17:02:48.867 回答