2013-04-09 157 views
0

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

// 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 
+0

'locationID_for_factualID'在做什么? – 2013-04-09 14:55:25

+0

如果找到包含事实ID的行,则locationID_for_factualID返回Location.idLocation,否则返回FALSE。所以基本上,如果该行存在,它会返回该位置的本地ID,否则返回FALSE。 – dbrateris 2013-04-09 15:00:48

回答

0

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

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

此问题的标准解决方案是使用事务。看看here这是怎么完成的。重要的部分是用locationID_for_factualIDINSERT包装SELECT,具有相同的交易,即在START TRANSACTIONCOMMIT之间。您可能必须更改locationID_for_factualID的实施以使用与以下INSERT相同的数据库连接。

另外,您可能想要在列factual_id上创建一个UNIQUE INDEX。如果尝试插入重复,则会使INSERT语句失败,从而防止相同的factual_id发生多次。

+0

谢谢,我可以做出这些改变,并立即调查。 但是,我确信这不是一个竞争条件,因为我只是测试了这一点,而且我是唯一的用户。我想有可能我使用的设备提出了两个请求,但我非常怀疑它。 – dbrateris 2013-04-09 15:17:08