2009-02-12 2 views
8

disconnect invalidates 1 active statement handle (either destroy statement handles or call finish on them before disconnecting)¿Por qué Apache se queja de que mi programa mod_perl "desconectar invalida 1 identificador de estado de cuenta activo"?

El siguiente código, que toma datos de MySQL es ejecutado con éxito, pero hará que Apache para generar el mensaje anterior en su registro de errores:

my $driver = "mysql"; 
my $server = "localhost:3306"; 
my $database = "test"; 
my $url  = "DBI:$driver:$database:$server"; 
my $user  = "apache"; 
my $password = ""; 

#Connect to database 
my $db_handle = DBI->connect($url, $user, $password) 
    or die $DBI::errstr; 

#SQL query to execute 
my $sql = "SELECT * FROM tests WHERE id=?"; 

#Prepare SQL query 
my $statement = $db_handle->prepare($sql) 
     or die "Couldn't prepare query '$sql': $DBI::errstr\n"; 

#Execute SQL Query 
$statement->execute($idFromSomewhere) 
    or die "Couldn't execute query '$sql': $DBI::errstr\n"; 

#Get query results as hash 
my $results = $statement->fetchall_hashref('id'); 

$db_handle->disconnect(); 
  • Habrá graves consecuencias por ignorar dicho error/advertencia? El código ha estado funcionando durante una semana sin efectos nocivos.

  • ¿Hay algún problema con el código o es solo una advertencia inofensiva?

Editar código

se ejecuta a través de mod_perl.

+0

Hola Brian, gracias por editar el título. Leí todos tus libros antes. – GeneQ

Respuesta

12

Debe llamar al $statement->finish(); antes del $db_handle->disconnnect();.

Normalmente no necesita llamar al finish, a menos que no obtenga todas las filas. Si obtiene todos los resultados en un bucle usando fetchrow_array, no llama a finalizar al final a menos que haya cancelado el ciclo.

No estoy seguro de por qué el controlador de MySQL no está terminando la instrucción después de fetchall_hashref. El manual sugiere que la consulta podría ser abortada debido a un error:

If an error occurs, fetchall_hashref returns the data fetched thus far, which may be none. You should check $sth->err afterwards (or use the RaiseError attribute) to discover if the data is complete or was truncated due to an error.

+0

Gracias, eso funcionó. Aunque leer el libro O'Reilly DBI y la documentación de Perl sugieren lo contrario. Resuelto en 16 minutos! ¡Ve a stackoverflow! – GeneQ

+0

Gracias por responder la pregunta "por qué" de mi pregunta Paul. ;-) Mereces tus 15k de karma. – GeneQ

+0

Los datos están bien. Ha sido golpeado por aproximadamente 1K personas continuamente durante una semana. Sí, la documentación lo dice. De todos modos, podría ser el controlador de MySQL. Después de llamar a finish() las advertencias dejaron de aparecer. Voy a actualizar a la última versión de DBI y MYSQL y ver qué pasa. – GeneQ

3

Esto es causado por el mango sigue siendo activo. Sin embargo, normalmente debería cerrarse, pero parece que no está obteniendo todos los datos del mismo. Desde el perldoc de DBI:

When all the data has been fetched from a SELECT statement, the driver should automatically call finish for you. So you should not normally need to call it explicitly except when you know that you've not fetched all the data from a statement handle. The most common example is when you only want to fetch one row, but in that case the selectrow_* methods are usually better anyway. Adding calls to finish after each fetch loop is a common mistake, don't do it, it can mask genuine problems like uncaught fetch errors.

+0

Gracias. Lo leí también y pensé que no era obligatorio. – GeneQ

+0

¡Pero él está llamando a fetchall_hashref, se supone que obtendrá todos los resultados! –

+0

buen punto, no entendí eso. La única manera de saberlo con certeza es verificando los errores en fetchall, supongo. – wds

0

Aunque probablemente no es la razón por la que tiene esta advertencia (que es lo que los manual demandas que es), que experimentaron la misma advertencia en circunstancias ligeramente diferentes y querían sugerirlo aquí en lugar de abrir mi propia pregunta.

Puede encontrarse en este escenario si realiza una consulta para buscar algunas filas, pero solo con la intención de saber si hay filas que coinciden o no. En mi circunstancia, actualizaremos las filas si se encuentra una coincidencia e inserte lo contrario.

Como no se hace nada con las filas que se encuentran, creo que esto constituye un escenario donde el seguimiento de la advertencia es apropiado. Por lo tanto, llamo al finish() en mi controlador de selección antes de desconectarme.

Descargo de responsabilidad: Siendo nuevo en DBI, existe un enfoque potencialmente mejor. Habría usado ->do() excepto the documentation señalando que debería no utilizarse cuando se ejecuta repetidamente - ¡también desaconsejí las declaraciones de SELECT por alguna razón, también!

Aquí es un poco de Perl pseudocódigo que muestra lo que aterricé en:

$selectHandler = $dbh->prepare($queryString) or die "Cannot prepare: ".$dbh->errstr; 
#Loop through a list of keys to check existence { 
    $selectHandler.execute($uniqueID); 
    $found = 0; 
    $found = $selectHandler->fetch(); 
    if (!$found) { 
     # Do an insert of $uniqueID 
    } else { 
     # Do an update of $uniqueID 
    } 
#} 
# Having not done anything with the selectHandler's result (when rows were 
# found) close it now that the loop is complete 
$selectHandler->finish(); # we don't need you any more select handler! 
$dbh->disconnect or warn "Disconnection error: $DBI::errstr\n"; 

Espero que esto ayude a alguien más y no dude en corregir mi enfoque si estoy engañosa nadie.

Cuestiones relacionadas