0

我在 MySQL 似乎插入一行两次时遇到了一些困难。- 基本上,我需要保存从远程数据源检索到的一些信息的本地副本。因此,当用户查看来自远程源的信息时,我会检查是否有需要存储的信息的本地副本。如果我没有本地副本,我会添加该信息的记录。- 我遇到的问题是,每插入 20-30 个插入,我就会得到一个重复。我使用 NOW 函数跟踪插入和更新时间,两条记录似乎同时插入。这是我的 PHP 代码,任何帮助将不胜感激,我很难过:

// We have the location, see if we have a local record for that location
        $idLocation = locationID_for_factualID($factual_id);
        if(!$idLocation) {
            // We do not have local information about the location, add it
            $mysqli = open_mysql_connection();
            $stmt = $mysqli->prepare("INSERT INTO Location (
                                                    factual_id,
                                                    dateAdded, 
                                                    dateModified, 
                                                    locationName,
                                                    latitude, 
                                                    longitude) 
                                                VALUES (?, NOW(), NOW(), ?, ?, ?)");
            if($stmt) {
                $stmt->bind_param("ssdd",$factual_id, $location["name"], doubleval($location["latitude"]), doubleval($location["longitude"]));
                $stmt->execute();
                // Check if the location was added
                if($stmt->affected_rows == 1){
                    $idLocation = locationID_for_factualID($factual_id);
                }
                $stmt->close();
                $mysqli->close();
            }
            else {
                return FALSE;
            }
        }

这里有两行似乎是背靠背插入的:

idLocation | factual_id | dateAdded | dateModified | locationName | latitude | longitude
520 | 5f79360f-330f-4035-ae75-e872ea14cfdd | 2013-04-09 14:36:55 | 2013-04-09 14:36:55 | Quiznos | 40.1802 | -74.0258
521 | 5f79360f-330f-4035-ae75-e872ea14cfdd | 2013-04-09 14:36:55 | 2013-04-09 14:36:55 | Quiznos | 40.1802 | -74.0258
4

1 回答 1

0

虽然我没有看到你的实现locationID_for_factualID,但我很确定它正在做类似的事情SELECT idLocation ... WHERE factual_id = '$factual_id'(不要忘记使用查询参数!)。

我可以想象你有一个竞争条件,即两个请求几乎同时使用相同的输入数据调用相同的脚本,然后调用函数locationID_for_factualID并且都找到了$idLocation == false。然后,两个请求都执行INSERT,你最终得到一个重复的记录。

此问题的标准解决方案是使用事务。看看这里是如何做到的。重要的部分是用相同的事务包装AND 的SELECT内部,即 between and 。您可能必须更改 的实现以使用与以下相同的数据库连接。locationID_for_factualIDINSERTSTART TRANSACTIONCOMMITlocationID_for_factualIDINSERT

顺便说一句,您可能希望UNIQUE INDEX在 factual_id 列上创建一个。这将防止相同的 factual_id 发生多次,INSERT如果它尝试插入重复则让语句失败。

于 2013-04-09T15:08:10.623 回答