2014-10-05 54 views
1

無論事務中的所有查詢都未成功執行,我的查詢都可以正常工作。我應該怎麼做才能使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

回答

4

當自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聲明,請小心這一點。它們不能用於交易。

0

爲@ gloomy.penguin說,你需要mysqli->begin_transaction()你在最後發送第一個事務,然後mysqli->commit()之前。

禁用自動提交,然後啓用自動提交是不必要的,除非你有更多的代碼稍後提交。

+0

通常你不需要那樣做。這是禁用自動提交的關鍵。它隱式地啓動一個事務直到調用commit()。 – 2014-10-05 21:59:01

+0

確定...但它有點囉嗦,因爲您必須隱式啓用自動提交功能。 – Christian 2014-10-05 22:01:04

相關問題