我有一个包含alias
和item_id
列的表格。这两个字段共同创建了一个独特的索引。
然后我有一些代码具有别名和项目ID ,并希望为其更新记录(或创建记录,如果它不存在)< / p>
//get the current stats for this item
$stats = $model->query(
'SELECT *, DATEDIFF(NOW(),decayed) as days_since_decay, DATEDIFF(NOW(),created) as days_active
FROM popularity_views
WHERE item_id = '.$query[0][$model->alias]['id'].'
AND alias = "'.$model->alias.'"'
);
if(empty($stats))
{
//create new entry
$insert = $model->query(
'INSERT INTO popularity_views (item_id, views, alias, created, decayed)
VALUES ('.$query[0][$model->alias]['id'].', 1, "'.$model->alias.'", NOW(), NOW())'
);
}
不知怎的,这个代码被调用两次,我不知道如何。即使它被调用两次虽然它无关紧要,因为你可以看到,我检查以确保在添加一个条目之前不存在。
但是当加载此页面时(如果在加载页面之前条目不存在),它会尝试两次创建一个条目并抛出 SQL错误1062:重复条目。这对我来说没有意义。此外,如果条目在页面加载之前就存在,那么它就足够聪明,根本不会尝试添加它。
有什么想法吗?
答案 0 :(得分:3)
如果此代码在两个单独的线程中执行(例如来自两个Web请求),则可能存在竞争条件。也就是说,事情按以下顺序发生:
您可以通过将查询序列包装在transaction(仅适用于InnoDB表类型)或使用REPLACE INTO
而不是单独的SELECT
和{{INSERT
来解决此问题。 1}}。
就个人而言,我会使用最后一个选项(REPLACE
),因为它可能表现最佳,并降低代码复杂性,但有很多方法可以做到。