我该怎么做才能使MySQL事务在我的代码中运行?

时间:2014-10-05 21:38:39

标签: php mysql mysqli

无论来自交易的所有查询是否都未成功执行,我的查询都会正常运行。

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

此代码正在运行并插入前两个查询,当然在第三个查询中断。

但是事务不起作用,无论它将插入每个有效的查询,我只想在所有三个查询都正确完成时插入。

我使用INNODB引擎和PHP 5.5

2 个答案:

答案 0 :(得分:4)

自从autocommit被禁用后隐式启动事务时,MySQL 在内部跟踪您执行的语句的成功状态。那是作为程序员的你的工作。因此,即使SOME BAD WRITTEN QUERY失败,前两个也会成功并且可以提交。

您必须相应地测试每个commit()rollback()的成功与否:

注意:您应该在SQL语句上调用real_escape_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);

最后一点。如果您仅针对单个事务禁用autocommit,然后重新启用它,请考虑仅启用autocommit 启用并明确开始和结束事务。只需致电

,而不是致电$this->mysqli->autocommit(false)及以后$this->mysqli->autocommit(true);
// 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

如果您的应用程序将使用大量事务,那么请务必禁用autocommit。在每次操作后,您都需要明确commit(),但我不会在一次交易后重新启用它。

关于DDL语句的注释 - MySQL无法回滚DDL语句,我相信调用一个中间事务将导致所有先前的语句被提交,即使您尚未明确调用commit()。如果您从代码中发出CREATE,ALTER,DROP语句,请注意这一点。它们不能用于交易。

答案 1 :(得分:0)

正如@ gloomy.penguin所说,在发送第一笔交易之前需要mysqli->begin_transaction(),然后在最后发送mysqli->commit()

禁用自动提交然后启用自动提交是不必要的,除非您有更多的代码稍后提交。