我应该怎么做才能使MySQL事务在我的代码中工作?

问题描述:

无论事务中的所有查询都未成功执行,我的查询都可以正常工作。我应该怎么做才能使MySQL事务在我的代码中工作?

$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

+0

你是否开始交易? 'mysqli-> begin_transaction()' – 2014-10-05 21:43:15

+0

@ gloomy.penguin当autocommit关闭时,你不需要明确地开始事务,只提交它们。 – 2014-10-05 21:53:14

+1

你不应该在SQL语句中调用'real_escape_string()'。你正确地绑定了参数,这就足够了。没有好处,并且试图逃避整个SQL语句可能会有一些伤害。只需使用'$ query =“INSERT INTO ... VALUES(?,?)”'来构建纯字符串。 – 2014-10-05 21:54:23

当自autocommit被禁用以来事务已被隐式启动时,MySQL是而不是内部跟踪您执行的语句的成功状态。那就是你的作为程序员工作。所以即使SOME BAD WRITTEN QUERY失败,前两个成功,并可以提交。

您必须测试每commit()或相应rollback()的成功:

注意:应呼叫real_escape_string()上的SQL语句。这对准备好的语句字符串可能有害,而且绝对不是必需的。

$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声明,请小心这一点。它们不能用于交易。

为@ gloomy.penguin说,你需要mysqli->begin_transaction()你在最后发送第一个事务,然后mysqli->commit()之前。

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

+0

通常你不需要那样做。这是禁用自动提交的关键。它隐式地启动一个事务直到调用commit()。 – 2014-10-05 21:59:01

+0

确定...但它有点啰嗦,因为您必须隐式启用自动提交功能。 – Christian 2014-10-05 22:01:04