【问题标题】:Quickest way to check for pre-existing record before insert [mysql_errno()]在插入 [mysql_errno()] 之前检查预先存在的记录的最快方法
【发布时间】:2012-02-13 06:17:13
【问题描述】:

我的问题将以电子邮件为例,但这可能适用于任何事情。


通常在注册新用户(包括插入他/她的电子邮件)之前,我会检查他/她的电子邮件是否已经存在于数据库中,如下所示:

$result = mysql_query("SELECT * FROM Users WHERE email = '".mysql_real_escape_string($email)"';");
if(!$result)
{
    die(mysql_error());
}

if(mysql_num_rows($result) > 0)
{
    die('<p>Email already in DB. <a....>Recover Email</a></p>');
}
else
{
    //insert new user data into Users table
}

既然我已经将我的用户表中的email 字段限制为UNIQUE,那么尝试先插入会不会更快,如果失败,请检查错误?像这样的:

$result = mysql_query(...);//insert new user data into Users table
if(!$result)
{
    if(mysql_errno()==$insert_unique_error)
    {
        $error = '<p>Email already in DB. <a....>Recover Email</a></p>';
    }
    else
    {
        $error = mysql_error();
    }
    die($die_str);
}

问题是我不知道$insert_unique_error 应该是什么。这些是唯一的错误代码I could find

SQLSTATE 值的前两个字符表示错误类别:

Class = '00' 表示成功。

Class = '01' 表示警告。

Class = '02' 表示“未找到”。这与游标的上下文相关,用于控制游标到达数据集末尾时发生的情况。 SELECT ... INTO var_list 不检索任何行的语句也会出现这种情况。

Class > '02' 表示异常。

【问题讨论】:

  • 你还在做一个单一的查询,那为什么呢?
  • @DamienPirsy 在正常情况下,我会在电子邮件不存在时进行两次查询(选择 + 插入),在电子邮件存在时进行一次查询(选择)。我建议的解决方案只查询电子邮件是否存在(插入)。
  • 我认为是:错误:1092 SQLSTATE: HY000 (ER_INSERT_INFO) 消息:记录:%ld 重复:%ld 警告:%ld 您的邮件字段应该是唯一的。
  • @DamienPirsy 我刚刚意识到我在复制和粘贴后忘记编辑一个部分。我已经编辑了问题。

标签: php mysql error-handling insert unique-constraint


【解决方案1】:

使用

INSERT IGNORE INTO Users VALUES(...);

在电子邮件字段上使用唯一键,然后使用 mysql_affected_rows() 检查行数;

这将导致对数据库的单个查询并排除 SELECT 和 INSERT 之间时间窗口的竞争条件

【讨论】:

  • 当然,mysql_affected_rows(),呃。为什么INSERT IGNORE ... 而不仅仅是INSERT ...?那是排除竞争条件的特定部分/关键字吗?
  • 如果遇到重复键,INSERT 将使查询失败,但 INSERT IGNORE 会在忽略行的情况下使其成功。您可以同时使用这两种方式,但根据我的喜好,故意让查询失败并不是最好的方式。
  • 我没有看到两者之间差异的重要性。如果我要使用mysql_affected_rows(),那么无论如何我都不会检查if(!$result),所以它是否成功/失败都不会打扰我,我只是要检查受影响的行。正确的?还是我在这里遗漏了什么?
  • 如果查询失败,您将得不到有效的 mysql_affected_rows()。在这种情况下,您需要检查错误代码。
【解决方案2】:

我相信 COUNT 是最快的方法之一。还请记住,在进行查询时,如果您只想测试它的存在,请不要执行

SELECT *

而是指定一个特定的字段

SELECT id

因此,您检索的数据不多。在使用 COUNT 的情况下:

SELECT COUNT(id) FROM Users WHERE email = 'emailaddress'

请参阅下面的链接了解如何在结果集中使用 COUNT

http://www.tizag.com/mysqlTutorial/mysqlcount.php

【讨论】:

  • 我同意使用ID 而不是*(我通常这样做,只是忘了把它放在问题中)并且COUNT() 可能比mysql_num_rows() 更快,但我真的希望完全避免SELECT
  • 啊,很公平,虽然它需要一个额外的查询(和更少的精简代码)我更喜欢先使用 select 而不是依赖于插入时抛出的错误,因为它更干净而且对我来说似乎更合乎逻辑.我实际上还没有遇到过额外选择会增加太多开销的情况
猜你喜欢
  • 1970-01-01
  • 2012-03-06
  • 2022-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-08
相关资源
最近更新 更多