2010-03-31 85 views
47

我試圖讓我的頭在MySQli周圍,我很困惑的錯誤報告。 我使用的庫MySQLi的返回值執行SQL時,「準備」語句來檢測錯誤,像這樣:MySQLi準備報表錯誤報告

$stmt_test = $mysqliDatabaseConnection->stmt_init(); 
if($stmt_test->prepare("INSERT INTO testtable VALUES (23,44,56)")) 
{ 
$stmt_test->execute(); 
$stmt_test->close(); 
} 
else echo("Statement failed: ". $stmt_test->error . "<br>"); 

但是,是的準備語句只檢測返回值如果在誤差SQL語句的準備工作並未檢測到執行錯誤?如果是這樣,我應該因此改變我的執行線來標記錯誤,以及這樣的:

if($stmt_test->execute()) $errorflag=true; 

然後爲了安全起見,我應該也可以在下面的語句執行後:

if($stmt_test->errno) {$errorflag=true;} 

。 ..或者我可以開始,並且MySQLi prepare語句的返回值捕獲與它定義的查詢的完整執行相關的所有錯誤。

感謝 Ç

+0

),而不是查詢()擺在首位當查詢字符串中沒有可變部分時?或者這只是一個簡單的例子? – VolkerK 2010-03-31 14:20:08

+0

是的,對不起。它被簡化以顯示我是如何難以理解從準備階段得到確切的錯誤報告的。 – Columbo 2010-03-31 14:25:48

回答

98

我在過去兩天之前兩次寫了這個(所以對我來說這是一個重複的,即使問題開始有點不同)。

mysqli的每種方法都可能失敗。你應該測試每個返回值。如果失敗了,考慮繼續處理一個未達到預期狀態的對象是否合理。 (可能不是在一個「安全」的狀態,但我認爲在這裏,這不是一個問題。)

由於只爲一操作的錯誤消息存儲每個連接/語句,你可能會失去有關什麼導致錯誤如果在出錯後繼續下去。您可能希望使用該信息讓腳本決定是否再次嘗試(僅是暫時性問題),更改內容或徹底解救(並報告錯誤)。它使調試更容易。

$stmt = $mysqli->prepare("INSERT INTO testtable VALUES (?,?,?)"); 
// prepare() can fail because of syntax errors, missing privileges, .... 
if (false===$stmt) { 
    // and since all the following operations need a valid/ready statement object 
    // it doesn't make sense to go on 
    // you might want to use a more sophisticated mechanism than die() 
    // but's it's only an example 
    die('prepare() failed: ' . htmlspecialchars($mysqli->error)); 
} 

$rc = $stmt->bind_param('iii', $x, $y, $z); 
// bind_param() can fail because the number of parameter doesn't match the placeholders in the statement 
// or there's a type conflict(?), or .... 
if (false===$rc) { 
    // again execute() is useless if you can't bind the parameters. Bail out somehow. 
    die('bind_param() failed: ' . htmlspecialchars($stmt->error)); 
} 

$rc = $stmt->execute(); 
// execute() can fail for various reasons. And may it be as stupid as someone tripping over the network cable 
// 2006 "server gone away" is always an option 
if (false===$rc) { 
    die('execute() failed: ' . htmlspecialchars($stmt->error)); 
} 

$stmt->close(); 

編輯:只是幾個音符,六年後....
mysqli擴展是完全有能力報告說,導致(mysqli的)錯誤0以外的通過異常的代碼操作,見mysqli_driver::$report_mode
die()是真的,非常粗糙,我甚至不會使用它,即使像這樣的例子了。
所以請只收取每個(mysql)操作可以失敗的事實;即使如果完全相同的事情進行了好幾千倍......

+2

謝謝。我剛做了一些測試,可以看到你在說什麼。如果我創建了一個將重複的主鍵值插入到表中的quesry,那麼僅檢查prepare就不會發現插入失敗。另一方面,如果我不檢查準備,那麼執行永遠不會發生(如果打開警告,我會得到一些警告)。所以我可以看到你是對的。謝謝。 – Columbo 2010-03-31 14:53:08

+0

噢,是的,約束是一個很好的例子。如果可能的話,我會給_the question_另一個+1作爲單獨的;-) – VolkerK 2010-03-31 14:57:38

+0

如果由於類型定義字符串中的元素數量不匹配而導致bind_param()失敗,我不能滿足此回答 – 2015-06-26 21:07:57

4

不知道這是否回答您的問題或沒有。對不起,對不起

要從mysql數據庫報告有關您的查詢的錯誤,您需要使用連接對象作爲焦點。

這樣:

echo $mysqliDatabaseConnection->error 

將回聲錯誤從MySQL發送有關查詢。

希望幫助

+0

謝謝。所以如果我爲實際的連接對象請求錯誤,那麼它會給我連接的最後一個錯誤。由於只有前面的所有步驟都成功,執行纔會成功,那麼這將告訴我是否一切順利。我猜也可以通過檢查Col Shrapnel在下面認可的執行命令的錯誤來產生相同的結果。因此,我是否認爲檢查準備聲明的成功/失敗標誌是否沒有真正的目的? – Columbo 2010-03-31 13:27:16

+0

我認爲你可能已經在上面得到了你的答案,但仍然會出於禮貌答覆。 VolekrK說,基本上Prepare可能會失敗,但它不會返回一個mysql錯誤。所以你需要找出爲什麼prepare失敗了,通過獲取mysql連接錯誤,它會告訴你準備語句中的查詢失敗。 我不確定執行命令錯誤。 – andyface 2010-04-06 09:38:13

11

完整性

你需要檢查都$mysqli$statement。如果它們是錯誤的,則需要分別輸出$mysqli->error$statement->error

效率

對於簡單的腳本,可以隨時終止,我用簡單的單行觸發一個PHP的錯誤與消息。對於更復雜的應用程序,應該激活錯誤警告系統,例如通過拋出異常。

用法示例1:簡單的腳本

# This is in a simple command line script 
$mysqli = new mysqli('localhost', 'buzUser', 'buzPassword'); 
$q = "UPDATE foo SET bar=1"; 
($statement = $mysqli->prepare($q)) or trigger_error($mysqli->error, E_USER_ERROR); 
$statement->execute() or trigger_error($statement->error, E_USER_ERROR); 

用法示例2:爲什麼要使用準備/執行(應用

# This is part of an application 
class FuzDatabaseException extends Exception { 
} 

class Foo { 
    public $mysqli; 
    public function __construct(mysqli $mysqli) { 
    $this->mysqli = $mysqli; 
    } 
    public function updateBar() { 
    $q = "UPDATE foo SET bar=1"; 
    $statement = $this->mysqli->prepare($q); 
    if (!$statement) { 
     throw new FuzDatabaseException($mysqli->error); 
    } 

    if (!$statement->execute()) { 
     throw new FuzDatabaseException($statement->error); 
    } 
    } 
} 

$foo = new Foo(new mysqli('localhost','buzUser','buzPassword')); 
try { 
    $foo->updateBar(); 
} catch (FuzDatabaseException $e) 
    $msg = $e->getMessage(); 
    // Now send warning emails, write log 
} 
+0

1. die()不應該被使用。 2. mysqli能夠自行拋出異常,請參閱mysqli_report()2.在每個*數據庫驅動的函數非常冗餘之後,編寫「發送警告電子郵件,寫入日誌」的代碼 – 2013-12-13 14:12:17

+0

@您的常識廢話。如果你使用自己執行的簡單腳本,那麼死掉就沒有問題。 – cmc 2013-12-13 14:16:28

+0

無論如何,你永遠不應該使用mysqli API,而只能包裝在一些更高級別的庫中。 – 2013-12-13 14:53:12