-2

複数の PHP スクリプトが並行して実行され、それぞれが同じテーブルの同じレコードに対して繰り返し UPDATE クエリを実行している場合、各クエリでテーブルが更新される前に「ラグ タイム」が発生する可能性はありますか?

基本的に、cron 経由で起動された PHP スクリプトのインスタンスが 5 ~ 6 個あり、並行して実行されています。各スクリプトは、テーブル内のすべてのレコードを取得し、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 スクリプトによって更新クエリが実行されてから、データベースが実際にレコードを更新するまでの間に、多少のタイムラグがあると思います。

本当ですか?もしそうなら、currentItemId複数のスクリプトが並行して実行されている場合でも、PHP スクリプトが常に最新のものだけを取得するようにするには、他にどのようなメカニズムを使用すればよいでしょうか? データベースヘルプの代わりにテキストファイルを使用しますか?

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 に答える