English 中文(简体)
检查重复条目是否使用 PDO 错误Info 结果
原标题:check for duplicate entry vs use PDO errorInfo result
  • 时间:2012-05-27 15:05:24
  •  标签:
  • php
  • mysql
  • pdo

我有一个 MySQL 表格, 该表格有一个用于电子邮件地址的字段, 其定义是独一无二的。 例如, 可以说我所有的表格都允许用户在表格中插入他们的电子邮件地址 。

由于电子邮件字段是独一无二的, 如果他们试图两次输入同一个电子邮件, 查询会失败。 我对两种情景之间的权衡表示好奇:

(1) 在执行插入前运行快速 SELECT 语句。 如果选中返回结果, 请通知用户, 不运行 INSERT 语句 。

(2)) 运行 INSERT 语句,并检查重复的输入错误

// snippet uses PDO
if (!$prep->execute($values))
{
    $err = $prep->errorInfo();
    if (isset($err[1]))
    {
        // 1062 - Duplicate entry
        if ($err[1] == 1062)
            echo  This email already exists. ;
    }
}

另外,请假定正常使用, 意思是重复的条目应该最小化。 因此, 在第一个假设情况下, 您显然有管理权来运行一个额外的查询, 以插入 < 坚固 > / 坚固 >, 而第二则您要依赖错误处理 。

还有,我很想知道关于编码风格的想法。 我的心说, 做一个防御程序员! 在插入前先检查数据! 我的大脑说, 嗯, 也许让 MySQL 帮你检查数据更好。

- 请注意这不是一个“我该怎么做”的问题,而是一个“我为什么要用特定的方式做这个”的问题。我包括的小代码片起作用了,但我好奇的是解决问题的最佳方法。

最佳回答

INSERT + check status > 应该是一个更好的办法。 如果有 SELECT + INSERT , 您可以在 SELECT 之间插入相同值的线条, 这意味着您也需要在表格锁中将这两个语句包起来。

在你的编码中,防守过度很容易犯错。 Python有一句俗话说 : “ 请求宽恕比请求允许更容易 ”, 而这一哲学并不完全针对Python。

问题回答

你可以执行这个 尝试捕捉块:

try {
   $prep->execute($values);
   // do other things if successfully inserted
} catch (PDOException $e) {
   if ($e->errorInfo[1] == 1062) {
      // duplicate entry, do something else
   } else {
      // an error other than duplicate entry occurred
   }
}

你也可以研究其他的替代方法, 比如“INSTERT IGNORE” 和“INSTERT...在DUUST KEUUUUST UPDATE” 尽管我认为这些是 MySQL 特定, 并且会与使用 PDO 的可携带性相悖, 如果这是你所关心的事情的话。

编辑:为了更正式地回答你的问题,对我而言,充分使用的解决方案1(防御程序员)有效地消除了唯一的限制点。所以我同意你的想法,让 MySQL 处理数据检查。

请注意,如果您有一个 AUTO_INCREONT 列,且您正在使用 InnoDB, 那么一个失败的 INSERT 将“ 下一个自动识别” 值加到“ 下一个自动识别” 值, 尽管没有添加新的行。 例如, 请参见 < href=" https://dev. mysql.com/doc/ref/refman/ “ https://dev. mysql. org/refman/ en/ innodb- uto- increment- dression. html" rel= “ nofolve norerer” >AUTO_ INCIntermment Magistration innoDB < / a> 。 这会导致 AUTO_ INCREONT id 中的空白, 这可能引起人们的关注, 如果您认为您可能用完问题的话, 。

所以,如果你期望试图插入一个已经存在的行是常见的,而且你想尽可能避免在 AUTO_INCIMON id 上出现漏洞,你可以先发制人地检查和例外处理:

$already_exists = false;
$stmt = $pdo->prepare("SELECT id FROM emails WHERE email = :email");
$stmt->execute(array( :email  => $email));
if ($stmt->rowCount() > 0) {
    $already_exists = true;
}
else {
    try {
        $stmt = $pdo->prepare("INSERT INTO emails (email) VALUES (:email)");
        $stmt->execute(array( :email  => $email));
    } catch (PDOException $e) {
        if ($e->errorInfo[1] == 1062) {
            $already_exists = true;
        } else {
            throw $e;
        }
    }
}

第一个查询确保如果我们确信电子邮件已经存在,我们不会试图插入电子邮件。 第二个查询试图插入电子邮件,如果电子邮件似乎还不存在的话。 我们还需要检查第二个查询中的例外情况,因为重复可能仍然发生在不大可能的种族状况下(多客户端或线条平行运行上面的片段) 。

这种方法使代码变得稳健, 但仍避免在AUTO_ INCREONT id 上产生漏洞, 但种族条件极少的情况除外。 如果试图插入现有电子邮件比试图插入新电子邮件更为常见, 这也是最快的方法。 如果尝试插入现有电子邮件是罕见的, 而且您不关心 AUTO_ INCREONT id 中的漏洞, 那么就不需要先发制人地检查了 。

对我来说,更简单的方法就是对照一系列重复的状态代码来检查错误代码。 这样你就不必担心PDO返回什么了。

$MYSQL_DUPLICATE_CODES=array(1062,23000);
try {
   $prep->execute($values);
   // do other things if successfully inserted
} catch (PDOException $e) {
   if (in_array($e->getCode(),$MYSQL_DUPLICATE_CODES)) {
      // duplicate entry, do something else
   } else {
      // an error other than duplicate entry occurred
   }
}

谢谢!

与其检查代码,我不如使用像这样的抓取块来捕捉主键重复条目, 使用错误代码 : 1062 重复条目

catch (PDOException $e) {

  if(str_contains($e,  1062 Duplicate entry )) {
       header("Location: login.php");
  }
die("Error inserting user details into database: " .  $e->getMessage());

}




相关问题
SQL SubQuery getting particular column

I noticed that there were some threads with similar questions, and I did look through them but did not really get a convincing answer. Here s my question: The subquery below returns a Table with 3 ...

please can anyone check this while loop and if condition

<?php $con=mysql_connect("localhost","mts","mts"); if(!con) { die( unable to connect . mysql_error()); } mysql_select_db("mts",$con); /* date_default_timezone_set ("Asia/Calcutta"); $date = ...

php return a specific row from query

Is it possible in php to return a specific row of data from a mysql query? None of the fetch statements that I ve found return a 2 dimensional array to access specific rows. I want to be able to ...

Character Encodings in PHP and MySQL

Our website was developed with a meta tag set to... <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> This works fine for M-dashes and special quotes, etc. However, I ...

Pagination Strategies for Complex (slow) Datasets

What are some of the strategies being used for pagination of data sets that involve complex queries? count(*) takes ~1.5 sec so we don t want to hit the DB for every page view. Currently there are ~...

Averaging a total in mySQL

My table looks like person_id | car_id | miles ------------------------------ 1 | 1 | 100 1 | 2 | 200 2 | 3 | 1000 2 | 4 | 500 I need to ...