防止在mySQL中选择相同的行

时间:2015-02-03 01:00:48

标签: php mysql transactions parallel-processing

我被赋予了创建一个" Mass Crawler"它完全依赖于数据库中的代理。以下是我试图实现的简单概述:

  • 1 x CronJob Bootstrap文件 - 这是向个人抓取工具文件发送50个并行 curl 请求的文件
  • 1 x单个Crawler文件 - 这应该从数据库中获取 UNIQUE 行(代理),而另一个进程没有被选中。

我已经使用mySQL查看TRANSACTIONS,但我仍然相信这样做无助于查询将在每个爬网程序进程的同一时间执行

以下是我个人抓取文件的想法:

$db = new MysqliDb("localhost", "username", "password", "database");

$db->connect();
$db->startTransaction();
$db->where("last_used", array("<" => "DATE_SUB(NOW(),INTERVAL 30 SECOND)"));
$proxies = $db->get("proxies", 1);
if(count($proxies) == 1) {

    //complete any scraping that needs to be done

    //update the database to say the proxy has just been used
    $db->where("id", $accounts[0]['id']);
    $db->update("proxies", array("last_used", date("Y-m-d H:i:s")));

    //commit the complete transaction
    $db->commit();
}
$db->disconnect();

以上示例是否是使用mySQL TRANSACTION功能的正确方法,并确保选择不同行的所有并行查询?

1 个答案:

答案 0 :(得分:3)

表中需要一个列,指示某个爬网程序进程正在使用该行。您的第一个SELECT应该查找WHERE in_use = 0;但是,它需要使用FOR UPDATE子句来锁定已处理的行。

SELECT *
FROM proxies
WHERE in_use = 0
LIMIT 1
FOR UPDATE;

我不知道如何使用您正在使用的数据库API编写该查询;您可能需要使用其功能来执行原始查询。

然后将该行更新为SET in_use = 1。通过在事务中执行这两个操作,可以确保没有其他进程可以获取该行。

处理完行后,可以SET in_use = 0