2010-03-31 15 views
47

Sto cercando di capire MySQli e sono confuso dalla segnalazione degli errori. Sto usando il valore di ritorno del MySQLi 'preparare' dichiarazione di rilevare gli errori durante l'esecuzione di SQL, in questo modo:MySQLi ha preparato la segnalazione degli errori

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

Ma, è il valore di ritorno della dichiarazione solo preparare rilevare se v'è un errore nella preperazione dell'istruzione SQL e non rilevamento errori di esecuzione? Se è così dovrei pertanto cambiare la mia linea di eseguire per errori di bandiera così come questo:

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

E poi giusto per essere sicuri dovrei anche fare il seguente testo dopo la dichiarazione ha eseguito:

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

. .. O ero OK per iniziare e il valore di ritorno sull'istruzione di preparare MySQLi cattura tutti gli errori associati all'esecuzione completa della query che definisce?

Grazie C

+0

Perché usate preparazione/esecuzione() al posto di query() in primo luogo quando non c'è una parte variabile nella stringa di query? O è solo un esempio semplicistico? – VolkerK

+0

Sì, mi dispiace. È stato semplificato per mostrare come stavo avendo difficoltà a capire dove ottenere una segnalazione definitiva degli errori da una situazione preparata. – Columbo

risposta

98

Ho scritto due volte prima che negli ultimi due giorni (quindi per me si tratta di un duplicato, anche se le domande hanno iniziato un po 'diverso).

Ogni metodo di mysqli può fallire. Dovresti testare ogni valore restituito. Se uno fallisce, pensa se abbia senso continuare con un oggetto che non si trova nello stato che ti aspetti che sia. (Potenzialmente non in uno stato "sicuro", ma penso che non è un problema qui.)

Poiché solo il messaggio di errore per l'ultima operazione viene memorizzato per ogni connessione/dichiarazione si potrebbe perdere informazioni su quello ha causato l'errore se continui dopo che qualcosa è andato storto. Potresti voler usare queste informazioni per consentire allo script di decidere se riprovare (solo un problema temporaneo), cambiare qualcosa o salvarlo completamente (e segnalare un bug). E rende il debug molto più facile.

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

edit: solo poche note sei anni più tardi ....
L'estensione mysqli è perfettamente in grado di operazioni che si traducono in un (mysqli) il codice di errore diverso da 0 via eccezioni segnalazione, vedi mysqli_driver::$report_mode.
die() è davvero, davvero rozzo e non lo userei nemmeno per esempi come questo.
Quindi, per favore, togliamo solo il fatto che l'operazione ogni (mysql) può fallire per una serie di ragioni;; anche se la stessa identica cosa è andata bene mille volte prima ....

+2

Grazie. Ho appena fatto alcuni test e posso vedere cosa stai dicendo. Se creo un quesry che inserisce un valore duplicato della chiave primaria in una tabella, controllare solo la preparazione non rivelerà che l'inserimento non è riuscito. D'altra parte, se non controllo la preparazione, l'esecuzione non avverrà mai (riceverò alcuni avvertimenti se gli avvisi sono attivati). Quindi posso vedere che hai ragione. Grazie. – Columbo

+0

Oh sì, i vincoli sono un esempio perfetto. Se possibile, darei la domanda_un altro +1 solo per quello ;-) – VolkerK

+0

Non riesco a mandare questa risposta su questa riga abbastanza –

4

Non sono sicuro se questo risponde alla tua domanda o no. Scusa se non

Per ottenere l'errore segnalato dal database mysql relativo alla query, è necessario utilizzare l'oggetto di connessione come elemento attivo.

così:

echo $mysqliDatabaseConnection->error 

associo l'errore di essere inviato da MySQL su query.

Speranza che aiuta

+0

Grazie. Quindi, se richiedo l'errore per l'oggetto di connessione reale, mi darà l'ultimo errore per quella connessione. Dal momento che l'esecuzione avrà successo solo se tutti i passaggi precedenti sono riusciti, questo mi dirà se tutto è andato bene. Suppongo che lo stesso risultato possa anche essere generato semplicemente controllando l'errore per il comando execute come approvato di seguito da Col Shrapnel. Ho ragione nel ritenere quindi che il controllo della dichiarazione di successo/fallimento della dichiarazione preparativa non abbia un vero scopo? – Columbo

+0

Penso che potresti già avere la tua risposta sopra, ma risponderai comunque per cortesia. Essenzialmente la preparazione può fallire, come ha detto VolekrK, ma non restituirà un errore mysql. Quindi è necessario scoprire perché preparare fallito ottenendo l'errore di connessione mysql che ti darà un'indicazione di dove la query nella tua istruzione preparativa ha avuto esito negativo. Non sono sicuro dell'errore del comando execute. – andyface

11

Completezza

È necessario controllare sia $mysqli e $statement. Se sono false, è necessario emettere rispettivamente $mysqli->error o $statement->error.

efficienza

Per semplici script che possono terminare, io uso semplice one-liners che attivano un errore di PHP con il messaggio. Per un'applicazione più complessa, invece, dovrebbe essere attivato un sistema di avviso di errore, ad esempio lanciando un'eccezione.

Uso Esempio 1: lo script semplice

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

esempio Uso 2: Applicazione

# 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() non dovrebbe mai essere usato. 2. mysqli è in grado di generare eccezioni da solo, vedere mysqli_report() 2. Scrittura del codice per "invia e-mail di avviso, registro di scrittura" dopo * ogni * funzione basata su database è terribilmente ridondante –

+0

@Il tuo Common Sense Bullshit. Se stai usando semplici script che esegui te stesso, muori, va bene. – cmc

+0

In ogni caso non si dovrebbe mai usare l'API mysqli così com'è, ma solo racchiusa in una libreria di livello superiore. –

Problemi correlati