-2

当有多个 PHP 脚本并行运行时,每个脚本都重复对同一张表中的同一条记录进行 UPDATE 查询,在每次查询更新表之前是否可能存在“滞后时间”?

我基本上有 5-6 个并行运行的 PHP 脚本实例,它们是通过 cron 启动的。每个脚本获取items表中的所有记录,然后遍历它们并处理它们。

但是,为了避免多次处理同一个项目,我将最后一个正在处理的项目的 id 存储在一个单独的表中。所以这就是我的代码的工作方式:

function getCurrentItem()
{
  $sql = "SELECT currentItemId from settings";
  $result = $this->db->query($sql);
  return $result->get('currentItemId');
}

function setCurrentItem($id)
{
   $sql = "UPDATE settings SET currentItemId='$id'";
   $this->db->query($sql);
}

$currentItem = $this->getCurrentItem();

$sql = "SELECT * FROM items WHERE status='pending' AND id > $currentItem'";
$result = $this->db->query($sql);
$items = $result->getAll();

foreach ($items as $i)
{
   //Check if $i has been processed by a different instance of the script, and if so, 
   //leave it untouched.
   if ($this->getCurrentItem() > $i->id) 
     continue;

   $this->setCurrentItem($i->id);
   // Process the item here
}

但是,尽管采取了所有预防措施,但大多数物品都被处理了不止一次。这让我认为 PHP 脚本运行的更新查询与数据库实际更新记录之间存在一些滞后时间。

这是真的吗?如果是这样,我应该使用什么其他机制来确保 PHP 脚本始终只获得最新的currentItemId,即使有多个脚本并行运行?会使用文本文件而不是 db 帮助吗?

4

2 回答 2

1

如果这是并行运行的,则几乎没有措施可以避免竞争条件。

script1:

getCurrentItem() yields Id 1234
...context switch to script2, before script 1 gets to run its update statement.

script2: 
getCurrentItem() yields Id 1234

两个脚本都处理 ID 1234

您想要更新和检查项目的状态一个全有或全无的操作,您不需要设置表,但您会做这样的事情(伪代码):

SELECT * FROM items WHERE status='pending' AND id > $currentItem

foreach($items as $i) {
 rows =  update items set status='processing' where id = $i->id and status='pending';
  if(rows == 0) //someone beat us to it and is already processing the item
    continue;
   process item..
 update items set status='done' where id = $i->id;
}
于 2010-03-20T02:25:48.217 回答
1

您需要的是任何线程都能够:

  • 查找待处理项目
  • 记录该项目现在正在处理(在settings表格中)

它需要同时完成这两项工作,中途没有任何其他线程干扰。

我建议将整个 SQL 放在一个存储过程中;这将能够将整个事物作为单个事务运行,从而使其免受竞争线程的影响。

于 2010-03-23T13:07:21.823 回答