2010-03-31 16 views
47

Estoy tratando de entender MySQli y estoy confundido por el informe de errores. estoy usando el valor de retorno de la MySQLi 'preparar' declaración para detectar errores en la ejecución de SQL, así:Declaraciones preparadas MySQLi error reporting

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

embargo, es el valor de retorno de la declaración preparar solamente detectar si hay un error en el preparación de la declaración SQL y no detectar errores de ejecución? Si es así debería, por tanto, cambiar de ejecutar la línea marcar los errores, así como esto:

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

Y a continuación, sólo para estar seguro debería también hacer lo siguiente después de la instrucción se ha ejecutado:

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

. ... ¿Estaba OK para comenzar y el valor de retorno en la declaración MySQLi prepare captura todos los errores asociados con la ejecución completa de la consulta que define?

Gracias C

+0

¿Por qué usan Preparar/Ejecutar() en lugar de la consulta() en el primer lugar cuando no hay una parte variable en su cadena de consulta? ¿O es esto solo un ejemplo simplificado? – VolkerK

+0

Sí, lo siento. Se simplificó para mostrar cómo estaba teniendo dificultades para entender dónde obtener informes de errores definitivos de un staement preparado. – Columbo

Respuesta

98

escribí esto dos veces antes en los últimos dos días (por lo que para mí es un duplicado a pesar de que las preguntas comenzaron un poco diferente).

Cada método de mysqli puede fallar. Debe probar cada valor de retorno. Si uno falla, piense si tiene sentido continuar con un objeto que no está en el estado que espera que sea. (Potencialmente no en un estado "seguro", pero creo que eso no es un problema aquí.)

Dado que sólo el mensaje de error de la última operación se almacena por conexión/declaración es posible que pierda información sobre lo provocó el error si continúas después de que algo salió mal. Es posible que desee utilizar esa información para dejar que el guión decida si volver a intentarlo (solo un problema temporal), cambiar algo o rescatar por completo (e informar un error). Y hace que la depuración sea mucho más fácil.

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

edición: sólo una pocas notas seis años más tarde ....
La extensión mysqli es perfectamente capaz de realizar operaciones que dan lugar a un (mysqli) código de error distinto de 0 a través de excepciones de informes, consulte mysqli_driver::$report_mode.
die() es muy, muy crudo y no lo usaría incluso para ejemplos como este.
Por favor, solo elimine el hecho de que todas y cada una de las operaciones (mysql) pueden fallar por una serie de razones; incluso si exactamente lo mismo fue bien mil veces antes ...

+2

Gracias. Acabo de hacer algunas pruebas y puedo ver lo que dices. Si creo un cuestionario que inserta un valor duplicado de clave principal en una tabla, al verificar solo la preparación no se revelará que la inserción falló. Por otro lado, si no reviso la preparación, entonces la ejecución nunca ocurrirá (obtendré algunas advertencias SI las advertencias están activadas). Entonces puedo ver que tienes razón. Gracias. – Columbo

+0

Oh sí, las restricciones son un ejemplo perfecto. Si es posible, le daré _la pregunta_ otro +1 solo por eso ;-) – VolkerK

+0

No puedo votar esta respuesta lo suficiente –

4

No estoy seguro si esto responda a su pregunta o no. Lo siento si no

Para obtener el error informado de la base de datos mysql acerca de su consulta, necesita utilizar su objeto de conexión como el foco.

manera:

echo $mysqliDatabaseConnection->error 

volvería a repetir el error que se envían desde MySQL sobre su consulta.

Esperamos que ayuda

+0

Gracias. Entonces, si solicito el error para el objeto de conexión real, entonces me dará el último error para esa conexión. Dado que la ejecución solo tendrá éxito si todos los pasos anteriores han tenido éxito, entonces esto me dirá si todo salió bien. Supongo que también se podría generar el mismo resultado simplemente verificando el error para el comando de ejecución como lo respalda Col Shrapnel. ¿Estoy en lo cierto al pensar, por lo tanto, que verificar el indicador de éxito/fracaso de la declaración de preparación no sirve para nada? – Columbo

+0

Creo que es posible que ya tenga su respuesta anterior, pero aún responderá por cortesía. Essentially Prepare puede fallar, como dijo VolekrK, pero no devolverá un error de mysql. Por lo tanto, debe averiguar por qué la preparación falló al obtener el error de conexión de mysql que le dará una indicación de dónde falló la consulta en su declaración de preparación. No estoy seguro acerca del error del comando de ejecución. – andyface

11

Integridad

Es necesario comprobar tanto $mysqli y $statement. Si son falsos, debe generar $mysqli->error o $statement->error, respectivamente.

Eficiencia

Para los scripts simples que puede terminar, me simple uso de una sola línea que desencadenan un error de PHP con el mensaje. Para una aplicación más compleja, un sistema de advertencia de error debería activarse en su lugar, por ejemplo lanzando una excepción.

uso Ejemplo 1: Simple 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); 

Ejemplo de uso 2: Aplicación

# 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() no se debe usar nunca. 2. mysqli es capaz de lanzar excepciones por sí mismo, vea mysqli_report() 2. Escribir código para "enviar correos electrónicos de advertencia, escribir registro" después de * cada * función basada en bases de datos es terriblemente redundante –

+0

@Su sentido común Bullshit. Si está utilizando scripts simples que ejecuta usted mismo, morir está bien. – cmc

+0

De todos modos, nunca deberías usar la API de mysqli tal como está, sino que solo estará incluida en alguna biblioteca de nivel superior. –

Cuestiones relacionadas