MySQLi 预准备语句错误报告

2022-08-30 08:12:55

我试图弄清楚MySQli,我对错误报告感到困惑。我正在使用MySQLi'prepare'语句的返回值来检测执行SQL时的错误,如下所示:

$stmt_test =  $mysqliDatabaseConnection->stmt_init();
if($stmt_test->prepare("INSERT INTO testtable VALUES (23,44,56)"))
{
 $stmt_test->execute();
 $stmt_test->close();
}
else echo("Statement failed: ". $stmt_test->error . "<br>");

但是,prepare 语句的返回值是否仅检测 SQL 语句的准备中是否存在错误而不检测执行错误?如果是这样,我应该因此更改我的执行行以标记错误,如下所示:

if($stmt_test->execute()) $errorflag=true;

然后为了安全起见,我还应该在语句执行后执行以下操作:

if($stmt_test->errno) {$errorflag=true;}

...或者,我是否可以从开始,并且 MySQLi prepare' 语句上的返回值捕获与它定义的查询的完整执行相关的所有错误?

谢谢 C


答案 1

mysqli的每种方法都可能失败。应测试每个返回值。如果一个失败,想想继续处理一个不处于你期望状态的对象是否有意义。(可能不处于“安全”状态,但我认为这不是问题。

由于每个连接/语句仅存储最后一个操作的错误消息,因此如果在出现问题后继续操作,则可能会丢失有关导致错误的原因的信息。您可能希望使用该信息让脚本决定是重试(只是暂时的问题)、更改某些内容还是完全挽救(并报告错误)。它使调试变得更加容易。

$stmt = $mysqli->prepare("INSERT INTO testtable VALUES (?,?,?)");
// prepare() can fail because of syntax errors, missing privileges, ....
if ( false===$stmt ) {
  // and since all the following operations need a valid/ready statement object
  // it doesn't make sense to go on
  // you might want to use a more sophisticated mechanism than die()
  // but's it's only an example
  die('prepare() failed: ' . htmlspecialchars($mysqli->error));
}

$rc = $stmt->bind_param('iii', $x, $y, $z);
// bind_param() can fail because the number of parameter doesn't match the placeholders in the statement
// or there's a type conflict(?), or ....
if ( false===$rc ) {
  // again execute() is useless if you can't bind the parameters. Bail out somehow.
  die('bind_param() failed: ' . htmlspecialchars($stmt->error));
}

$rc = $stmt->execute();
// execute() can fail for various reasons. And may it be as stupid as someone tripping over the network cable
// 2006 "server gone away" is always an option
if ( false===$rc ) {
  die('execute() failed: ' . htmlspecialchars($stmt->error));
}

$stmt->close();

六年后,仅仅几个音符...

mysqli扩展完全能够通过异常报告导致(mysqli)错误代码(0以外的)操作,请参阅mysqli_driver::$report_mode
die()真的非常非常粗糙,我甚至不会再使用它了。
因此,请只带走每个(mysql)操作都可能由于多种原因而失败的事实;即使完全相同的事情在一千次之前进展顺利....


答案 2

完整性

您需要同时检查 和 。如果它们是假的,则需要分别输出或。$mysqli$statement$mysqli->error$statement->error

效率

对于可能终止的简单脚本,我使用简单的单行代码来触发消息的PHP错误。对于更复杂的应用程序,应改为激活错误警告系统,例如通过引发异常。

用法示例 1:简单脚本

# This is in a simple command line script
$mysqli = new mysqli('localhost', 'buzUser', 'buzPassword');
$q = "UPDATE foo SET bar=1";
($statement = $mysqli->prepare($q)) or trigger_error($mysqli->error, E_USER_ERROR);
$statement->execute() or trigger_error($statement->error, E_USER_ERROR);

使用示例 2:应用程序

# This is part of an application
class FuzDatabaseException extends Exception {
}

class Foo {
  public $mysqli;
  public function __construct(mysqli $mysqli) {
    $this->mysqli = $mysqli;
  }
  public function updateBar() {
    $q = "UPDATE foo SET bar=1";
    $statement = $this->mysqli->prepare($q);
    if (!$statement) {
      throw new FuzDatabaseException($mysqli->error);
    }

    if (!$statement->execute()) {
      throw new FuzDatabaseException($statement->error);
    }
  }
}

$foo = new Foo(new mysqli('localhost','buzUser','buzPassword'));
try {
  $foo->updateBar();
} catch (FuzDatabaseException $e)
  $msg = $e->getMessage();
  // Now send warning emails, write log
}

推荐