php - 如何在没有并发问题的情况下选择行并更新它们?

标签 php mysql select transactions sql-update

我正在使用 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/

相关文章:

php - 在 where 子句中仅选择年份和月份

mysql 收集 1 :n relation into one record

MYSQL 在使用 GROUP BY 时显示不正确的行

php - Laravel Vue - 在 json 响应上获得 Eloquent

mysql - 无法在 elementaryos 上安装 mysql 5.6

mysql - 使用 mysql 数据库上的访问信息连接到 MySQL 数据库

php - 为什么 SELECT 语句在找不到匹配记录时似乎返回了 "NULL"值以外的值

php - Geckoboard 数据集 PHP cURL API

php - 通过 Zend Framework 的 select() 传递带空格的列名

php - 使用正则表达式分隔组中的字符串