MySql 查询延迟时间/死锁?
当有多个 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
即使有多个脚本并行运行?使用文本文件而不是数据库会有帮助吗?
When there are multiple PHP scripts running in parallel, each making an UPDATE query to the same record in the same table repeatedly, is it possible for there to be a 'lag time' before the table is updated with each query?
I have basically 5-6 instances of a PHP script running in parallel, having been launched via cron. Each script gets all the records in the items
table, and then loops through them and processes them.
However, to avoid processing the same item more than once, I store the id of the last item being processed in a separate table. So this is how my code works:
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
}
But despite of all the precautions, most items are being processed more than once. Which makes me think that there is some lag time between the update queries being run by the PHP script, and when the database actually updates the record.
Is it true? And if so, what other mechanism should I use to ensure that the PHP scripts always get only the latest currentItemId
even when there are multiple scripts running in parallel? Would using a text file instead of the db help?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果并行运行,则几乎没有措施可以避免竞争条件。
两个脚本都处理 Id 1234
你想要更新并检查项目的状态,这是一个全有或全无的操作,你不需要设置表,但你会做这样的事情(伪代码):
If this is run in parallell there's little measure to avoid race conditions.
And both scripts process Id 1234
You'd want to update and check status of the item an all-or-nothing operation, you don't need the settings table, but you'd do something like this (pseudo code):
您需要的是任何线程都能够:
settings
表中)并且它需要一次性完成这两件事,中途没有任何其他线程干扰。
我建议将整个 SQL 放在存储过程中;这将能够将整个事情作为单个事务来运行,这使得它免受竞争线程的影响。
What you need is for any thread to be able to:
settings
table)And it needs to do both of those in one go, without any other thread interfering half-way through.
I recommend putting the whole SQL in a stored procedure; that will be able to run the entire thing as a single transaction, which makes it safe from competing threads.