在创建条目之前检查条目是否存在仍然会引发重复条目错误

时间:2011-09-13 20:35:21

标签: mysql cakephp cakephp-1.3

我有一个包含aliasitem_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:重复条目。这对我来说没有意义。此外,如果条目在页面加载之前就存在,那么它就足够聪明,根本不会尝试添加它。

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

如果此代码在两个单独的线程中执行(例如来自两个Web请求),则可能存在竞争条件。也就是说,事情按以下顺序发生:

  1. 在线程#1中选择执行
  2. 在线程#2中选择执行
  3. 线程#1中的插入执行
  4. 线程#2中的插入执行(返回错误)
  5. 您可以通过将查询序列包装在transaction(仅适用于InnoDB表类型)或使用REPLACE INTO而不是单独的SELECT和{{INSERT来解决此问题。 1}}。

    就个人而言,我会使用最后一个选项(REPLACE),因为它可能表现最佳,并降低代码复杂性,但有很多方法可以做到。