PHP MySQL在唯一索引上创建重复记录失败


PHP MySQL create duplicate record on unique index strange fail

动作:创建一个唯一键的重复表记录

Good:唯一键正在工作,因为没有创建重复记录。

坏:我在PHP中使用的mysqli函数并没有以我期望的方式失败。

Meta:我有一些PHP(运行5.3.6)处理从AJAX POST请求在Mysql(5.5.9)表中创建新记录。身份验证、输入清洗和验证是在我所共享的代码范围之外处理的。response函数还处理以有效格式打印响应。我要插入的表有一个自动递增的id列和一个唯一的name列。

// connect to server
$mysqli = new mysqli("localhost", "dbuser", 'dbpassword', "database");
if(mysqli_connect_errno()) {
    $response["message"] = "unable to connect to the MySQL server at 'localhost' as 'dbuser' using a password or select the database 'database' because ".mysqli_connect_errno();
    respond($response);
}
// build and run query
if ($stmt = $mysqli -> prepare("INSERT INTO `database`.`table` (`id`, `name`) VALUES (NULL, ?);")) {
    $stmt -> bind_param("s", $inputs["name"]);
    $success = $stmt -> execute();
    if ($success) {
        $response["status"] = "success";
        $response["id"] = $mysqli -> insert_id;
        respond($response);
    } else {
        $response["message"] = "failed to insert because ".$stmt -> error;
    }
    $stmt -> close();
} else {
    $response["message"] = "unable to build query because ".$mysqli -> error;
    respond($response);
}
$mysqli -> close();

当插入一个新的唯一名称时,它按预期工作,但当试图插入一个新的重复名称时,它不返回任何东西。我期望

$stmt -> execute();

失败,所以我将返回一个解释错误的响应。这段代码没有这样做。我发现返回由于重复而创建失败的唯一方法是在close语句之前添加2行代码,如下所示:

// connect to server
$mysqli = new mysqli("localhost", "dbuser", 'dbpassword', "database");
if(mysqli_connect_errno()) {
    $response["message"] = "unable to connect to the MySQL server at 'localhost' as 'dbuser' using a password or select the database 'database' because ".mysqli_connect_errno();
    respond($response);
}
// build and run query
if ($stmt = $mysqli -> prepare("INSERT INTO `database`.`table` (`id`, `name`) VALUES (NULL, ?);")) {
    $stmt -> bind_param("s", $inputs["name"]);
    $success = $stmt -> execute();
    if ($success) {
        $response["status"] = "success";
        $response["id"] = $mysqli -> insert_id;
        respond($response);
    } else {
        $response["message"] = "failed to insert because ".$stmt -> error;
    }
    $stmt -> close();
} else {
    $response["message"] = "unable to build query because ".$mysqli -> error;
    respond($response);
}
$response["message"] = "Duplicate";
respond($response);
$mysqli -> close();

我不明白的是,当查询按预期运行时,没有返回重复的响应。当查询因为试图在唯一键上插入重复而失败时,这将返回重复的响应。

问题:为什么一个成功的插入没有在代码块的末尾运行响应函数?

问题:为什么由于试图在唯一键上插入重复而导致插入失败而没有抛出异常或失败?

我也试过把整个东西包装在一个try catch块中,但它没有任何帮助,因为它没有抛出任何异常。如果您能就此事提供任何线索,我将不胜感激。

问题:为什么成功插入没有在代码块末尾运行响应函数?

我假设你的respond方法有一个exitdie在它的某个地方停止执行。

问题:为什么由于尝试在唯一键上插入重复而导致插入失败而没有抛出异常或失败?

我认为这与你的if语句中的逻辑有关。

如果你的过程进入else语句

$response["message"] = "failed to insert because ".$stmt -> error;

不发送任何响应(从未调用respond函数)。第二个例子之所以有效,是因为代码每次都到达那个点(因为它在最后一个else语句之外)。如果在上面的行之后移动对respond的调用,您可能会发现它像预期的那样返回消息。完整代码可能如下所示:

// connect to server
$mysqli = new mysqli("localhost", "dbuser", 'dbpassword', "database");
if(mysqli_connect_errno()) {
    $response["message"] = "unable to connect to the MySQL server at 'localhost' as 'dbuser' using a password or select the database 'database' because ".mysqli_connect_errno();
    respond($response);
}
// build and run query
if ($stmt = $mysqli -> prepare("INSERT INTO `database`.`table` (`id`, `name`) VALUES (NULL, ?);")) {
    $stmt -> bind_param("s", $inputs["name"]);
    $success = $stmt -> execute();
    if ($success) {
        $response["status"] = "success";
        $response["id"] = $mysqli -> insert_id;
        respond($response);
    } else {
        $response["message"] = "failed to insert because ".$stmt -> error;
        respond($response); // <-- this is the bit you need
    }
    $stmt -> close();
} else {
    $response["message"] = "unable to build query because ".$mysqli -> error;
    respond($response);
}
$mysqli -> close();

尝试从$stmt->errorCode()$stmt->errorInfo()获取错误信息