php - 回滚 MySQL 查询

标签 php mysql database rollback

如果我在链上有多个查询,在基于 IF 的结构上,如下所示:

$query1 = mysqli_query("query here");

if(!query1){
    //display error
} else {
    $query2 = mysqli_query("another query here");
    if(!query2){
        //display error
        //rollback the query1
    } else {
        query3 = mysqli_query("yet again another query");
        if(!query3) {
            //display error
            //rollback the query2
            //rollback the query1
        } else {
            query4 = mysqli_query("eh.. another one");
            if(!query4){
                //display error
                //rollback the query3
                //rollback the query2
                //rollback the query1
            } else {
                return success;
            }
        }
    }
}

如果下一个查询失败,是否有回滚上一个查询的最佳方法? 否则我将成功完成前 2 个查询,它编辑了数据库,但是 3° 失败了,所以 3° 和 4° 没有编辑数据库,结果是它被破坏了。

我想过类似的事情:

    ...
    $query2 = mysqli_query("another query here");
    if(!query2){
        //display error
        $rollback = mysqli_query("query to rollback query1");
    } else {
        query3 = mysqli_query("yet again another query");
        if(!query3) {
            //display error
            $rollback = mysqli_query("query to rollback query2");
            $rollback = mysqli_query("query to rollback query1");
        } else {
        ...

但是上面的方法允许更多的机会使更多的查询失败。 还有其他更有效的方法吗?

最佳答案

这就是我用 mysqli 做的:

配置 mysqli(在应用程序开始的某个地方)在查询失败时抛出异常。

mysqli_report(MYSQLI_REPORT_STRICT);

这样你就不需要所有的if .. elseif .. else

$connection->begin_transaction();
try {
    $result1 = $connection->query("query 1");
    // do something with $result1

    $result2 = $connection->query("query 2");
    // do something with $result2

    $result3 = $connection->query("query 3");
    // do something with $result3

    // you will not get here if any of the queries fails
    $connection->commit();
} catch (Exception $e) {
    // if any of the queries fails, the following code will be executed
    $connection->rollback(); // roll back everything to the point of begin_transaction()
    // do other stuff to handle the error
}

更新

通常用户不关心他的操作为什么失败。如果查询失败,那绝不是用户的错。这要么是开发者的错,要么是环境的错。因此,不应该根据哪个查询失败来呈现错误消息。

请注意,如果用户输入是失败查询的来源,则

  1. 您没有正确验证输入
  2. 您的查询不是 injection安全(如果输入可能导致 SQL 错误,它也可以用来破坏您的数据库。)

但是 - 我并不是说没有原因 - 我只是不知道。因此,如果您希望错误消息取决于哪个查询失败,您可以执行以下操作:

$error = null;
$connection->begin_transaction();
try {
    try {
        $result1 = $connection->query("query 1");
    } catch (Exception $e) {
        $error = 'query 1 failed';
        throw $e;
    }
    // do something with $result1

    try {
        $result2 = $connection->query("query 2");
    } catch (Exception $e) {
        $error = 'query 2 failed';
        throw $e;
    }
    // do something with $result2

    // execute more queries the same way

    $connection->commit();
} catch (Exception $e) {
    $connection->rollback();
    // use $error to find out which query failed
    // do other stuff to handle the error
}

关于php - 回滚 MySQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42724708/

相关文章:

php - WordPress 帖子按类别和日期排序

php - laravel 查询构建器中 select 的内部查询?

mysql - SQL 查询关于 union 和 concat

mysql - 如果我们有 2 个唯一列,我们应该选择哪一列作为主键

sql - 在 Aginity Workbench SQL 中选择 1% 的样本

php - 相同的字符串加盐代码给出不同的结果

mysql - 我应该如何从主机访问命名卷?

mysql - 在c中使用mysql时出错

c# - 设计问题 - 用 C# 更新多行 - 关注多次往返性能

php - 如何更新 MySQL 两列查找表,其中每个字段都是主键