我基本上有一个cron文件,它同时向{1}}发送一个文件,因此是并行的,在cron文件中。
我的 cron 文件看起来像这样(发送并行请求)
multi_curl
然后在我的<?php
require "files/bootstrap.php";
$amount = array(
"10","11","12","13","14"
);
$urls = array();
foreach($amount as $cron_id) {
$urls[] = Config::$site_url."single_cron.php?cron_id=".$cron_id;
}
$pg = new ParallelGet($urls);
?>
内我得到了以下查询
single_cron.php
即使我在查询中有SELECT *
FROM accounts C JOIN proxies P
ON C.proxy_id = P.proxy_id
WHERE C.last_used < DATE_SUB(NOW(), INTERVAL 1 MINUTE)
AND C.status = 1
AND C.running = 0
AND P.proxy_status = 1
AND C.test_account = 0
ORDER BY uuid()
LIMIT 1
,他们似乎仍然会以某种方式拾取同一行,防止这种情况的最佳方法是什么?我听说过交易
我正在使用的当前框架是PHP,所以如果有任何解决方案可行,那么我可以自由地使用解决方案。
答案 0 :(得分:1)
检查select for update命令。这可以防止其他并行查询通过阻止选择同一行,直到您执行commit
。所以你的选择应该包括last_process_time > 60
之类的条件,你应该在选择它之后更新该行,将last_processed_time设置为当前时间。也许您有一种不同的机制来检测最近是否选择/处理了一行,您也可以使用它。关于它的重要一点是select for update
会对行进行锁定,所以即使你并行运行查询,它们也会被mysql服务器序列化。
这是确保您没有2个查询选择同一行的唯一方法 - 即使您的uuid()订单工作正常,您也可以选择2个并行查询中的相同行
使用交易执行此操作的正确方法是:
START TRANSACTION;
SELECT *
FROM accounts C JOIN proxies P
ON C.proxy_id = P.proxy_id
WHERE C.last_used < DATE_SUB(NOW(), INTERVAL 1 MINUTE)
AND C.status = 1
AND C.running = 0
AND P.proxy_status = 1
AND C.test_account = 0
LIMIT 1;
(假设您的帐户表中有一个列'ID',用于唯一标识行)
UPDATE accounts
set last_used=now(), .... whatever else ....
where id=<insert the id you selected here>;
COMMIT;
将首先执行到达服务器的查询,并锁定返回的行。此时将阻止所有其他查询。现在你更新你想要的任何东西。提交后,将执行其他进程的其他查询。他们将找不到您刚刚更改的行,因为last_used < ...
条件不再正确。其中一个查询将找到一行,将其锁定,其他查询将再次被阻止,直到第二个进程执行提交。这一直持续到一切都结束。
您也可以在会话中将自动提交设置为0,而不是START TRANSACTION
。并且不要忘记这仅在使用InnoDB表时才有效。如果您需要更多详细信息,请查看我给您的链接。