2010-03-31 42 views
47

Tôi đang cố gắng để có được đầu của tôi xung quanh MySQli và tôi bối rối bởi báo cáo lỗi. Tôi đang sử dụng giá trị trả về của MySQLi 'chuẩn bị' tuyên bố để phát hiện sai sót khi thực hiện SQL, như thế này:Báo cáo lỗi báo cáo chuẩn bị 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>"); 

Nhưng, là giá trị trở lại của báo cáo kết quả chuẩn bị chỉ phát hiện nếu có một lỗi trong preperation của câu lệnh SQL và không phát hiện lỗi thực thi? Nếu vậy tôi nên do đó thay đổi thực đơn hàng của mình lỗi cờ cũng như thế này:

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

Và sau đó chỉ để được an toàn nên tôi cũng làm như sau sau khi báo cáo kết quả đã thực hiện:

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

. ..Or là tôi OK để bắt đầu với và giá trị trả về trên MySQLi chuẩn bị 'tuyên bố nắm bắt tất cả các lỗi liên quan đến việc thực hiện đầy đủ các truy vấn nó định nghĩa?

Cảm ơn C

+0

Tại sao bạn nên sử dụng chuẩn bị/thực hiện() thay vì truy vấn() ở nơi đầu tiên khi không có phần biến trong chuỗi truy vấn của bạn? Hay đây chỉ là một ví dụ đơn giản? – VolkerK

+0

Có, xin lỗi. Nó đã được đơn giản hóa để cho thấy làm thế nào tôi đã gặp khó khăn trong việc hiểu nơi để có được báo cáo lỗi dứt khoát từ một staement chuẩn bị. – Columbo

Trả lời

98

tôi đã viết này hai lần trước đây trong hai ngày vừa qua (do đó đối với tôi nó là một bản sao mặc dù những câu hỏi bắt đầu một chút khác nhau).

Mỗi phương pháp mysqli đều có thể bị lỗi. Bạn nên kiểm tra từng giá trị trả lại. Nếu một thất bại, suy nghĩ về việc liệu nó có ý nghĩa để tiếp tục với một đối tượng không ở trong trạng thái mà bạn mong đợi. (Có thể không ở trạng thái "an toàn", nhưng tôi nghĩ đó không phải là vấn đề ở đây.)

Vì chỉ có thông báo lỗi cho hoạt động cuối cùng được lưu trữ cho mỗi kết nối/câu lệnh, bạn có thể mất thông tin về số nếu bạn tiếp tục sau khi có sự cố. Bạn có thể muốn sử dụng thông tin đó để cho tập lệnh quyết định có nên thử lại hay không (chỉ là vấn đề tạm thời), thay đổi một số thứ hoặc giải cứu hoàn toàn (và báo cáo lỗi). Và nó làm cho việc gỡ lỗi dễ dàng hơn rất nhiều.

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

chỉnh sửa: chỉ là một vài lưu ý sau sáu năm ....
Phần mở rộng mysqli là hoàn toàn có khả năng hoạt động mà kết quả trong một (mysqli) mã lỗi khác 0 qua ngoại lệ báo cáo, xem mysqli_driver::$report_mode.
die() thực sự, thực sự thô và tôi sẽ không sử dụng nó ngay cả đối với các ví dụ như thế này nữa.
Vì vậy, xin vui lòng, chỉ lấy đi thực tế là mỗi và mọi hoạt động (mysql) có thể không thành công vì một số lý do; thậm chí nếu điều tương tự cũng xảy ra hàng nghìn lần trước đó ....

+2

Cảm ơn. Tôi vừa làm một số thử nghiệm và có thể thấy những gì bạn đang nói. Nếu tôi tạo ra một quesry mà chèn một giá trị khóa chính trùng lặp vào một bảng sau đó kiểm tra chuẩn bị chỉ sẽ không tiết lộ rằng chèn không thành công. Mặt khác, nếu tôi không kiểm tra chuẩn bị thì thực thi sẽ không bao giờ xảy ra (tôi sẽ nhận được một số cảnh báo nếu cảnh báo được bật). Vì vậy, tôi có thể thấy rằng bạn đã đúng. Cảm ơn. – Columbo

+0

Ồ vâng, các ràng buộc là một ví dụ hoàn hảo. Nếu có thể tôi sẽ cho _the câu hỏi_ +1 khác cho điều đó một mình ;-) – VolkerK

+0

Tôi không thể trả lời câu trả lời này đủ –

4

Không chắc nếu điều này trả lời câu hỏi của bạn hay không. Xin lỗi nếu không

Để nhận được thông báo lỗi từ cơ sở dữ liệu mysql về truy vấn của bạn, bạn cần sử dụng đối tượng kết nối làm trọng tâm.

vậy:

echo $mysqliDatabaseConnection->error 

sẽ echo lỗi được gửi từ mysql về truy vấn của bạn.

Hy vọng rằng sẽ giúp

+0

Cảm ơn. Vì vậy, nếu tôi yêu cầu lỗi cho đối tượng kết nối thực tế thì nó sẽ cho tôi lỗi cuối cùng cho kết nối đó. Kể từ khi thực hiện sẽ chỉ thành công nếu tất cả các bước trước đó đã thành công thì điều này sẽ cho tôi biết nếu tất cả đã đi tốt. Tôi cho rằng kết quả tương tự cũng có thể được tạo ra bằng cách chỉ kiểm tra lỗi cho lệnh thực hiện như được xác nhận dưới đây bởi Col Shrapnel. Tôi có suy nghĩ đúng đắn vì vậy việc kiểm tra cờ thành công/thất bại của câu lệnh chuẩn bị không có mục đích thực sự? – Columbo

+0

Tôi nghĩ rằng bạn có thể đã có câu trả lời của bạn ở trên, nhưng vẫn sẽ trả lời trong lịch sự. Về cơ bản Chuẩn bị có thể thất bại, như VolekrK đã nói, nhưng nó sẽ không trả lại lỗi mysql. Vì vậy, bạn cần phải tìm hiểu lý do tại sao chuẩn bị thất bại bằng cách nhận được lỗi kết nối mysql mà sẽ cung cấp cho bạn một dấu hiệu của nơi mà các truy vấn trong tuyên bố chuẩn bị của bạn không thành công. Tôi không chắc chắn về lỗi lệnh thi hành. – andyface

11

Đầy đủ

Bạn cần phải kiểm tra cả $mysqli$statement. Nếu sai, bạn cần xuất tương ứng $mysqli->error hoặc $statement->error.

Hiệu quả

Đối với kịch bản đơn giản mà có thể chấm dứt, tôi sử dụng đơn giản một lớp lót kích hoạt một lỗi PHP với thông điệp. Đối với một ứng dụng phức tạp hơn, một hệ thống cảnh báo lỗi nên được kích hoạt thay vào đó, ví dụ bằng cách ném một ngoại lệ.

Cách sử dụng Ví dụ 1: Đơn giản script

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

Cách sử dụng Ví dụ 2: Application

# 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() không nên được sử dụng bao giờ hết. 2. mysqli có thể tự ném các ngoại lệ, xem mysqli_report() 2. Viết mã cho "gửi email cảnh báo, ghi nhật ký" sau * mọi chức năng cơ sở dữ liệu định hướng là dư thừa một cách khủng khiếp –

+0

@Your Common Sense Bullshit. Nếu bạn đang sử dụng các kịch bản lệnh đơn giản mà bạn thực thi bản thân thì chết là tốt. – cmc

+0

Dù sao bạn không bao giờ nên sử dụng mysqli API như là, nhưng chỉ được gói trong một số thư viện cấp cao hơn. –

Các vấn đề liên quan