2009-02-12 15 views
8

disconnect invalidates 1 active statement handle (either destroy statement handles or call finish on them before disconnecting)Perché Apache si lamenta che il mio programma mod_perl "disconnect invalida 1 handle di istruzione attivo"?

Il codice seguente, che prende i dati da MySQL viene eseguito con successo, ma farà sì che Apache per generare il messaggio di cui sopra nel suo log degli errori:

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(); 
  • Ci saranno conseguenze disastrose ignorando il detto errore/avvertimento? Il codice è in esecuzione da una settimana senza effetti negativi.

  • C'è qualcosa che non va con il codice o è solo un avvertimento innocuo?

Modifica

codice viene eseguito tramite mod_perl.

+0

Ehi Brian, grazie per aver modificato il titolo. Ho letto tutti i tuoi libri prima. – GeneQ

risposta

12

È necessario chiamare $statement->finish(); prima del $db_handle->disconnnect();.

Normalmente non è necessario chiamare finish, a meno che non si ottengano tutte le righe. Se ottieni tutti i risultati in un ciclo utilizzando fetchrow_array, non si chiama fine alla fine, a meno che non si interrompa il ciclo.

Non sono sicuro del motivo per cui il driver MySQL non sta terminando la dichiarazione dopo un fetchall_hashref. Il manuale suggerisce che la query potrebbe essere che termina a causa di un errore:

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

Grazie, ha funzionato. Sebbene leggere il libro O'Reilly DBI e la documentazione Perl suggeriscano il contrario. Risolto in 16 minuti! Vai allo stackoverflow! – GeneQ

+0

Grazie per aver risposto alla parte "perché" della mia domanda, Paul. ;-) Ti meriti il ​​tuo 15k di karma. – GeneQ

+0

I dati vanno bene. È stato picchiato da circa 1K di persone continuamente per una settimana. Sì, la documentazione dice così. Ad ogni modo, potrebbe essere solo il driver MySQL. Dopo aver chiamato finish() gli avvisi hanno smesso di apparire. Ho intenzione di aggiornare all'ultima build di DBI e MYSQL e vedere cosa succede. – GeneQ

3

questo è causato dalla maniglia essendo ancora attivo. Normalmente dovrebbe chiudersi, ma non sembra che stia recuperando tutti i dati da esso. Dal perldoc sulla 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

Grazie. Ho letto anche quello e ho pensato che non fosse obbligatorio. – GeneQ

+0

Ma sta chiamando fetchall_hashref - questo dovrebbe ottenere tutti i risultati! –

+0

buon punto, non l'ho capito. L'unico modo per sapere con certezza è controllare gli errori su fetchall immagino. – wds

0

Anche se probabilmente non la ragione che hai questo avvertimento (che è ciò che i manual sostiene che è), ho sperimentato lo stesso avvertimento in circostanze leggermente diverse e volevano suggerire qui piuttosto che aprire la mia stessa domanda.

Potresti trovarti in questo scenario se esegui una query per recuperare alcune righe, ma solo per l'intenzione di sapere se ci sono o meno righe corrispondenti. Nella mia circostanza, aggiorneremo le righe se viene trovata una corrispondenza e inseriamo altrimenti.

Poiché non viene eseguito nulla con le righe trovate, ritengo che ciò costituisca uno scenario in cui seguire la guida dell'avviso è appropriato. Pertanto, chiamo finish() sul mio gestore di selezione prima di disconnettermi.

Disclaimer: Essendo nuovo di DBI, c'è potenzialmente un approccio migliore. Avrei usato ->do() eccetto che ha sottolineato che dovrebbe essere non essere utilizzato quando eseguito ripetutamente - anche scoraggiato erano le dichiarazioni SELECT per qualche motivo, pure!

Ecco alcuni pseudocodice perl che mostra quello che ho atterrato su:

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

Spero che questo aiuti qualcun altro e non esitate a correggere il mio approccio se sto fuorviante nessuno.

Problemi correlati