首页 > 解决方案 > 为什么我的 PHP 代码有时会在我的 MySQL 数据库中创建多行?

问题描述

我的 MySQL 数据库有 180k 行...其中 7k 是重复的。数据是通过 POST 的 javascript Web 应用程序运行的 PHP (5.6.30) 脚本创建的。

也就是说,它们具有相同的数据和相同的时间戳。

这是运行以创建行的代码:

$log->lwrite('Do NOT have extCommentID / author: ' . $authorID);
             $query = "INSERT INTO anno_feedback (anno_fb_author_id, anno_fb_recip_ext_id, anno_fb_recip_ext_name, anno_fb_recip_avatar_url, anno_fb_ext_id, anno_fb_ext_sys_id, anno_fb_lib_id, anno_fb_group_id, anno_fb_comment_id, anno_fb_app_source, anno_fb_platform, anno_fb_use_custom, anno_fb_comment_text, anno_fb_url_target, anno_fb_word_target) VALUES ($authorID, '". $recipientID ."', '" .$recipientName . "', '" .$recipientAvatarURL . "', '" . $extCommentID . "', $sysID, $libID, $groupID, $commentID, '" . $appSource . "', '" . $platform . "',$commentUseCustom,'" . $commentText . "','" . $urlTarget ."','" . $wordTarget ."')";
             // $newFbID = mysqli_insert_id($connection);           //  Get ID of newly created row...
        //  //  echo "\n\nRunning query to create Group - $query";
         // $log->lwrite('New commentID created: ' . $newFbID);
    }       //  END else for no existing feedback

    //  NOW, regardless, run query...
    if(mysqli_query($connection, $query)){
        $newFbID = mysqli_insert_id($connection);           //  Get ID of newly created row...
        $log->lwrite('New commentID created: ' . $newFbID);
        echo "\n\nCreated/updated feedback row...for row: " . $newFbID;
    }   else {
        echo "ERROR: Was not able to execute $query. " . mysqli_error($connection);
    }

还有一个日志示例:

[16/Oct/2018:07:13:27] (saveFeedback) -------------开始为用户/commentID 保存反馈:5222 / 23093 [16/Oct/2018:07:13 :27] (saveFeedback) 没有 extCommentID / 作者:5222 [16/Oct/2018:07:13:27] (saveFeedback) 新的 commentID 创建:177444 [16/Oct/2018:07:13:27] (saveFeedback ) -------------开始为用户/commentID 保存反馈:5222 / 23093 [16/Oct/2018:07:13:27] (saveFeedback) 没有 extCommentID/作者:5222 [ 16/Oct/2018:07:13:27] (saveFeedback) 新评论 ID 创建:177445

这些行(177444 和 177445)是重复的。

我不相信我在通过 POST 命令运行 PHP 的 Web 应用程序中存在问题(不是重复的侦听器或表单提交)。我认为 PHP 有时会运行两次——可能是并发或服务器负载问题?

PHP/MySQL 解决方案可以使用哪些策略来避免这种情况?我已经阅读了有关 INSERT IGNORE 的信息,但我必须检查一个文本字段和一个日期字段才能知道是否正在创建重复项——这感觉很昂贵。

任何方向都值得赞赏 - 可能有一些我不知道的最佳实践来确保创建单行。很高兴提供更多细节。

标签: phpmysqlmysqli

解决方案


PHP/MySQL 解决方案可以使用哪些策略来避免这种情况?我已经阅读过 INSERT IGNORE 但我必须检查文本字段和日期字段才能知道是否正在创建重复项 - 这感觉很昂贵

制作唯一索引。通常,您不能使文本字段唯一(如果您指的是文本类型,而不是 VarChar)。这通常是绊倒人们的绊脚石。如果您需要检查文本字段是否唯一,您如何拥有唯一索引..

一种方法是您可以创建数据的散列,然后使其唯一,这几乎一样好。你只需要维护哈希。例如,如果他们编辑帖子,您将不得不更新哈希,但这真的没什么大不了的。

例如:

        $hash = hash('sha1', $date.$text);

然后在数据库中创建一个新字段,该字段是CHAR(40)具有UTF8_bin排序规则的唯一索引。SHA1 是 40 字节长,然后UTF8_bin是二进制格式,这使得搜索区分大小写。哈希区分大小写。

实际上,这会将您的大块文本(和日期)压缩成一个 40 个字符的哈希值,您可以对其进行唯一索引。那么就不可能有重复。SHA1 哈希非常快,我曾经计时过,在我的 PC 上大约每秒 30,000 次哈希。我完全忘记了,所以我可能会走得更远,但它有很多,远远超过我需要担心的时间。

INSERT IGNORE这经常被误解,它所做的只是忽略错误。如果您没有正确的唯一索引,那么您将不会因为重复而收到错误,并且它根本不会帮助您。它并不比普通插入慢,但它可以抑制除了唯一索引失败之外的错误。

另一件事是,您必须先删除重复项,然后才能修复表。您还必须返回并为已保存的那些记录创建散列。这应该不会太难,只要确保在进行任何更改之前备份表即可。

我不相信我在通过 POST 命令运行 PHP 的 Web 应用程序中存在问题(不是重复的侦听器或表单提交)。我认为 PHP 有时会运行两次——可能是并发或服务器负载问题?

它可以像双击提交按钮一样简单。我曾经有一个办公室工作人员的鼠标不好,每次她单击提交按钮时都会双击它。由于并发性,您不能仅依靠代码检查来保持其唯一性。

使用数据库中的唯一字段,您可以使用INSRT IGNOREINSERT ON DUPLICATE UPDATEREPLACE INTO,所有这些都可以避免实际错误进入应用程序,并且不要插入重复项。不过,所有人都有自己的小怪癖。例如INSERT ON DUPLICATE,即使在更新时也会增加自动增量 ID 计数器(而不是行的 ID),这没什么大不了的,但很高兴知道。Replace 删除当前行并插入一个新行,因此如果不包含在查询中,自动增量 ID 将更改。

希望有帮助!


推荐阅读