当有多个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帮助吗?
答案 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放在存储过程;这将能够将整个事务作为单个事务运行,从而使其不受竞争线程的影响。