从PHP中的事务失败中恢复

时间:2018-08-09 16:54:41

标签: php mysqli

SQL查询可能由于多种原因而失败,即使同一查询之前运行了100次也没有问题。我想检测一下交易失败的天气。我发现了两种方法:

1:使用大量if else语句

$mysqli->begin_transaction();
$stmt = $mysqli->prepare("INSERT INTO testtable VALUES (?,?,?)");
if ( false===$stmt ) {
  $mysqli->rollback();
  issueInternalError();
}

$rc = $stmt->bind_param('iii', $x, $y, $z);
if ( false===$rc ) {
  $mysqli->rollback();
  issueInternalError();
}
$rc = $stmt->execute();
if ( false===$rc ) {
  $mysqli->rollback();
  issueInternalError();
}else{
$mysqli->commit();
}

$stmt->close();

2:在try catch块中执行查询

try{
    $mysqli->begin_transaction();
    $stmt = $mysqli->prepare("INSERT INTO testtable VALUES (?,?,?)");
    $stmt->bind_param('iii', $x, $y, $z);
    $stmt->execute();
    $mysqli->commit();

}catch(Exception $e){
    $mysqli->rollback();
    issueInternalError();
}

使用try / catch将代码减半,并使其真正可读,但是第二个代码是否可以正确捕获所有可能的错误?或更完善的是,如果存在错误,将始终执行issueInternalError()吗?

更新:

我已将此代码添加到php文件的开头

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

我在测试中得到的结果参差不齐:

已成功捕获此类错误:

    $mysqli->begin_transaction();
    $stmt = $mysqli->prepare("INSERT INTO testtable VALUES (?,?,?)");
    $stmt->bind_param('iiissss', $x, $y, $z); //error here is successfully catched

但这不是

    $mysqli->begin_transaction();
    $stmt = $mysqli->prepare("INSERT INTO testtable VALUES (?,?,?)");
    $stmt->bind_param('iii', $x, $y, $z,""); //error not catched

看起来第二个不是由mysqli引起的,因此不会引发。

1 个答案:

答案 0 :(得分:1)

您的 try-catch 不会捕获所有错误。它只会捕获异常。 PHP 中的错误和异常是有区别的。

以下 try-catch 将仅捕获异常:

try {
    // ...
} catch(Exception $e) {
    // ...
}

要捕获异常和错误,您可以使用 Throwable 接口。作为旁注,最好始终为 PHP 中的类和接口提供完全指定的名称。

try {
    // ...
} catch(\Throwable $e) {
    // ...
}

Mysqli 可以抛出异常和错误。异常通常在mysqli 无法处理命令或MySQL 服务器端执行命令失败时触发。这些异常是 mysqli_sql_exception 异常类的实例。

如果 PHP 端有程序员错误,例如参数数量不正确或参数无效,那么 mysqli 将触发 PHP 错误。这些可能是各种错误,但通常,它们都源自基类 Error

警告:在 PHP 8 之前,许多错误只是警告。这些现在已经被正确分类。此外,在 mysqli 中修复了许多软件错误,这些错误在应该发生时不会触发异常。为获得最佳效果,请使用最新的 PHP 版本。