1
votes

If I have multiple queries on chain, on a structure based on IFs, like this:

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

Is there a best way to rollback the previous query, if the next one fails? Otherwise I'm gonna have the first 2 query successfull, which edited the database, but the 3° failed, so 3° and 4° didn't edit the dabatase, with the result of having it corrupted.

I thought about something like:

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

But the above method grants even more chances to fail more queries. Is there any other more effective methods?

1
To 'rollback' any query, use begin tran first and the use of commit or rollback, I advice you to search for transactionsNeobugu
How exactly I do that? any reference/guide?Net Jacker
I'll have a look, thanksNet Jacker
You never passed the db connection to any of your queries btw, should that be next to actual syntax/code.Funk Forty Niner

1 Answers

2
votes

This is how i would do it with mysqli:

Configure mysqli (somewehere at the begining of your application) to throw exceptions when a query fails.

mysqli_report(MYSQLI_REPORT_STRICT);

This way you will not need all the 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
}

Update

Usually the user don't care about, why his action failed. If a query fails, it's never the users fault. It's either the fault of the developer or of the environment. So there shouldn't be a reason to render an error message depending on which query failed.

Note that if the users intput is the source of the failed query, then

  1. you didn't validate the input properly
  2. your queries are not injection safe (If the input can cause an SQL error it can also be used to compromise your DB.)

However - I don't say there can't be reasons - I just don't know any. So if you want your error message depend on which query failed, you can do the following:

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