2010-10-15 10 views
6

Esiste un problema noto con SQLite che genera un errore "database bloccato" per una seconda query in una singola transazione quando si utilizza Perl DBD :: SQLite? Scenario: Linux, Perl DBI, AutoCommit => 0, una subroutine con due blocchi di codice (utilizzando i blocchi per localizzare i nomi delle variabili). Nel primo blocco di codice viene creato un handle di query da prepare() su un'istruzione select, viene eseguito() e il blocco viene chiuso. Il secondo blocco di codice viene creato da un altro handle di query preparando un'istruzione di aggiornamento e frequentemente (il 30% delle volte) SQLite/DBI fornisce un errore bloccato del database in questa fase. Penso che l'errore si verifichi durante prepare() e non durante l'esecuzione().Perché SQLite fornisce un "database bloccato" per una seconda query in una transazione quando si utilizza DBD :: SQLite di Perl?

Il mio lavoro è di eseguire il commit dopo la prima query. (Chiamare finire sulla prima query non ha aiutato). Preferisco non impegnarmi per diversi motivi relativi all'eleganza e alle prestazioni. Il codice originale ha funzionato bene per molti anni con Postgres come database. Ho provato sqlite_use_immediate_transaction senza alcun effetto.

In tutte le altre situazioni, ho trovato che SQLite si comporta molto bene, quindi sospetto che si tratti di una svista nel driver DBD, piuttosto che un problema con SQLite. Purtroppo, il mio codice attuale è una grande pila di script e moduli, quindi non ho un caso di test di un singolo file.

+0

Puoi mostrarci il tuo piccolo test case che dimostra il problema? –

risposta

6

Non correlato a questo in alcun modo è: Transaction and Database Locking dal DBD::SQLite perldoc?

transazione da AutoCommit o begin_work è bello e utile, ma a volte si può ottenere un fastidioso "database è bloccato" errore. Questo di solito accade quando qualcuno inizia una transazione e prova a scrivere su un database mentre un'altra persona sta leggendo dal database (in un'altra transazione). Potresti rimanere sorpreso, ma SQLite non blocca un database quando inizi una transazione normale (differita) per massimizzare la concorrenza. Si riserva un blocco quando si rilascia una dichiarazione per scrivere, ma finché non si tenta effettivamente di scrivere con una dichiarazione di commit, consente ad altre persone di leggere dal database. Tuttavia, la lettura dal database richiede anche il blocco condiviso, e questo impedisce di darti il ​​blocco esclusivo che hai riservato, quindi ottieni l'errore "database è bloccato" e altre persone otterranno lo stesso errore se provano a scrivere in seguito, come hai ancora un blocco in sospeso. busy_timeout non aiuta in questo caso.

Per evitare questo, impostare un tipo di transazione in modo esplicito. È possibile emettere una transazione immediata (o iniziare una transazione esclusiva) per ogni transazione oppure impostare l'attributo sqlite_use_immediate_transaction database handle su true (a partire da 1.30_02) per utilizzare sempre una transazione immediata (anche quando si utilizza semplicemente begin_work o si spegne AutoCommit.) .

my $dbh = DBI->connect("dbi:SQLite::memory:", "", "", { 
    sqlite_use_immediate_transaction => 1, 
}); 

Si noti che questo funziona solo quando tutti i collegamenti utilizzare la stessa transazione (non differita). Vedere http://sqlite.org/lockingv3.html per dettagli di blocco.