MySql查询滞后时间/死锁?

时间:2010-03-20 02:03:14

标签: php sql mysql database race-condition

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

我基本上有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帮助吗?

2 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:1)

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

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

它需要一次完成这两个任务,没有任何其他线程干扰中途。

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