回滚MySQL查询

时间:2017-03-10 17:48:54

标签: 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°没有编辑dabatase,导致其被破坏。

我想到了类似的东西:

    ...
    $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 {
        ...

但是上述方法更有可能使更多查询失败。 还有其他更有效的方法吗?

1 个答案:

答案 0 :(得分:2)

这就是我使用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
}

<强>更新

通常用户不关心,为什么他的行动失败了。如果查询失败,那么用户从不会出错。它既是开发者的错,也是环境的错。因此,不应该根据哪个查询失败来呈现错误消息。

请注意,如果用户intput是失败查询的来源,那么

  1. 您没有正确验证输入
  2. 您的查询不是injection安全的(如果输入可能导致SQL错误,它也可能用于危害您的数据库。)
  3. 然而 - 我不能说不可能是原因 - 我根本就不知道。因此,如果您希望错误消息取决于哪个查询失败,您可以执行以下操作:

    $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
    }