作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 PHP 和 MySQL 5.6.17 (InnoDB) 实现一个队列,我想选择前 N 个匹配行,然后将它们标记为正在处理。
我需要将行标记为正在处理,因为查询是由多个并行运行的脚本执行的(因此我需要防止脚本选择相同的行)。
我写了以下查询:
START TRANSACTION;
SELECT id, col2, col3
FROM table
WHERE col4 = 1 AND date_update_started < UTC_TIMESTAMP() - INTERVAL 12 HOUR
ORDER BY col5 DESC, col6 ASC
LIMIT 100 FOR UPDATE;
#update the above selected rows to mark them as being processed
UPDATE table SET date_update_started = UTC_TIMESTAMP() WHERE id IN (
SELECT id, col2, col3 #same query as above
FROM table
WHERE col4 = 1 AND date_update_started < UTC_TIMESTAMP() - INTERVAL 12 HOUR
ORDER BY col5 DESC, col6 ASC
LIMIT 100
);
COMMIT;
但是,在测试查询的更新部分时,我收到以下错误:
[Err] 1235 - This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
如何修改此查询,使其选择前 N 个匹配行并更新这些行上的 date_update_started
列,以便并行执行此查询的脚本不会选择它们?
最佳答案
确保脚本的每个实例都有一个唯一的 ID。您可以在它运行时将其作为命令行参数传递。
向队列表中添加一列:
scriptId INT DEFAULT NULL
- 用它来锁定一些行;保留锁定它们的脚本的 ID。这段代码锁定了一些行:
UPDATE `table`
SET lockId = 123 # Replace '123' (in PHP) with the ID of the script that runs the query
WHERE lockId IS NULL
AND ... # put your own conditions here to select the entries you want to process
LIMIT 100 # change '100' with the number of entries you want to lock in a batch
然后运行:
SELECT *
FROM `table`
WHERE lockId = 123 # The same value as above
获取锁定的行。
处理每一行后,您可以将其从表中删除或将状态字段设置为“已处理”并使用它在上面的锁定查询中将其过滤掉。
备注:如果您绝对确定处理脚本在处理过程中不会崩溃,则此方法很有效。如果它崩溃,它会使行锁定。如果在下一次运行时它使用相同的 script ID
,它将尝试处理锁定的行。这可以通过在脚本退出时解锁行来解决。
关于php - 如何在没有并发问题的情况下选择行并更新它们?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27648987/
我是一名优秀的程序员,十分优秀!