【问题标题】:Checking to see if entry exists before creating it still throws duplicate entry error在创建之前检查条目是否存在仍然会引发重复条目错误
【发布时间】:2011-09-13 20:35:20
【问题描述】:

我有一个表格,其中包含 aliasitem_id 列。这两个字段共同创建了一个唯一索引。

然后我有一些代码有一个 alias 和一个 item id 并且想要为它更新一条记录(或者如果它不存在则创建一条记录)

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

有什么想法吗?

【问题讨论】:

    标签: mysql cakephp cakephp-1.3


    【解决方案1】:

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

    1. 在线程 #1 中执行选择
    2. 在线程 #2 执行中选择
    3. 插入线程 #1 执行
    4. 插入线程 #2 执行(返回错误)

    您可以通过将查询序列包装在 transaction 中(仅适用于 InnoDB 表类型)或使用 REPLACE INTO 而不是单独的 SELECTINSERT 来解决此问题。

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

    【讨论】:

    • 谢谢,我也弄清楚了为什么会发生双重请求。它正在使用相对 URL 而不是绝对 URL 加载我的网站图标。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-22
    • 1970-01-01
    • 2012-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    相关资源
    最近更新 更多