检查重复条目与使用PDO errorInfo结果

Jos*_*ett 34 php mysql pdo

我有一个MySQL表,其中有一个电子邮件地址字段,定义为唯一.对于此示例,假设我的所有表单都允许用户将其电子邮件地址插入表中.

由于电子邮件字段是唯一的,因此如果查询尝试两次输入相同的电子邮件,则查询失败.我很好奇两种情况之间的权衡:

1)SELECT在执行插入之前运行快速语句.如果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.';
    }
}
Run Code Online (Sandbox Code Playgroud)

另外,请假设正常使用,这意味着重复的条目应该是最小的.因此,在第一个场景中,您显然需要为每个插入运行额外查询的开销,而在第二个场景中,您依赖于错误处理.

另外,我很想听听有关编码风格的想法.我心里说'做一名防守程序员!在插入之前检查数据!' 虽然我的大脑说'嗯,也许最好让MySQL负责为你检查数据'.

编辑 - 请注意这不是"我该怎么做"的问题,而是"我为什么要这样做"的问题.我包含的小代码片段有效,但我很好奇的是解决问题的最佳方法.

Dan*_*nna 56

您可以使用try catch块执行此操作:

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
   }
}
Run Code Online (Sandbox Code Playgroud)

您还可以查看其他替代方法,例如"INSERT IGNORE"和"INSERT ... ON DUPLICATE KEY UPDATE" - 尽管我认为这些是特定于MySQL的,并且会违反使用PDO的可移植性,如果这是您关心的问题.

编辑:为了更正式地回答你的问题,对我来说,完全使用的解决方案#1(防御性程序员)首先有效地消除了唯一约束的点.所以我同意你让MySQL负责数据检查的想法.

  • 根据PHP文档,`PDOException-> errorInfo [1]`也是特定于MySQL的 - 它是`特定于驱动程序的错误代码`.你需要再次检查`PDOException-> errorInfo [0]`,这是SQLSTATE代码,它应该或多或少(尽管通常更少)可移植. (12认同)
  • 但是使用`$ e-> errorCode()=== 23000`而不是`errorInfo [1]`有什么问题? (8认同)

lan*_*nzz 10

INSERT+检查状态应该是更好的方法.使用SELECT+,INSERT您可以让另一个线程在SELECT和之间插入相同的值INSERT,这意味着您还需要将这两个语句包装在表锁中.

在你的编码中过于防守很容易犯错误.Python有这样的说法:"要求宽恕比要求许可更容易",而且这种哲学并不是特定于Python的.