简体   繁体   中英

What should I do to make MySQL transactions work in my code?

My queries are working no matter if all queries from transaction weren't successfully executed.

$this->mysqli->autocommit(FALSE);

$query = $this->mysqli->real_escape_string("INSERT INTO `product` (`name`, `price`) VALUES (?,?)");
            $prod = $this->mysqli->prepare($query);
            $prod->bind_param("ss", $name,$price);
            $prod->execute();

$query = $this->mysqli->real_escape_string("INSERT INTO `member` (`user`, `address`) VALUES (?,?)");
            $prod = $this->mysqli->prepare($query);
            $prod->bind_param("ss", $user,$address);
            $prod->execute();

$query = $this->mysqli->real_escape_string(" SOME BAD WRITTEN QUERY") ;
            $prod = $this->mysqli->prepare($query);
            $prod->execute();


if (!$this->mysqli->commit())
{
    print("\nTransaction commit failed\n");
    $this->mysqli->rollback();
}
$this->mysqli->autocommit(TRUE);

This code is working and inserting first two queries, of course breaks on third.

But transaction isn't working, no matter what it will insert every query that works, and I want to insert only if all three queries are done properly.

I use INNODB engine and PHP 5.5

When the transaction has been implicitly started since autocommit was disabled, MySQL is not internally tracking the success state of the statements you execute. That is your job as the programmer. So even if SOME BAD WRITTEN QUERY fails, the previous two succeeded and can be committed.

You must test for the success of each and commit() or rollback() accordingly:

Note: You should not call real_escape_string() on the SQL statements. It is potentially harmful, and definitely not necessary for the prepared statement string.

$this->mysqli->autocommit(FALSE);

$query = "INSERT INTO `product` (`name`, `price`) VALUES (?,?)";
$prod = $this->mysqli->prepare($query);
$prod->bind_param("ss", $name,$price);

// Store success/fail in a variable (returns TRUE on success)
$success1 = $prod->execute();

$query = "INSERT INTO `member` (`user`, `address`) VALUES (?,?)";
$prod = $this->mysqli->prepare($query);
$prod->bind_param("ss", $user,$address);

// Store success/fail in a variable (returns TRUE on success)
$success2 = $prod->execute();

$query = " SOME BAD WRITTEN QUERY";
$prod = $this->mysqli->prepare($query);

// Store success/fail in a variable (returns FALSE on failure)
$success3 = $prod->execute();

// Now check if all 3 succeeded and commit() if they did
if ($success1 && $success2 && $success3)
{
  $this->mysqli->commit();
}
// Or rollback() if they didn't
else
{
    print("\nTransaction commit failed\n");
    $this->mysqli->rollback();
}
$this->mysqli->autocommit(TRUE);

A final note. If you are only disabling autocommit for a single transaction then re-enabling it, consider just leaving autocommit enabled and explicitly beginning and ending the transaction. Instead of calling $this->mysqli->autocommit(false) and later $this->mysqli->autocommit(true); , just call

// Don't disable autocommit
// Start it...
$this->mysqli->begin_transaction();
// Do your 3 queries as above and test for success
// Then commit or rollback
$this->mysqli->commit();
// (or rollback)
// Now, no need to re-enable auto-commit

If your application will use lots of transactions, then by all means disable autocommit . You'll need to explicitly commit() after every action, but I wouldn't disable it just to reenable it after one transaction.

And a note about DDL statements - MySQL cannot rollback DDL statements, and I believe calling one mid-transaction will cause all the previous statements to be committed, even though you have not yet explicitly called commit() . So beware of this if you are issuing CREATE,ALTER,DROP statements from your code. They cannot be used with transactions.

as @gloomy.penguin says, you need to mysqli->begin_transaction() before you send the first transaction and then mysqli->commit() at the end.

disabling autocommit and then enabling autocommit is unnecessary unless of course you have more code that commits later.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM