2010-10-15 9 views
6

Gibt es ein bekanntes Problem mit SQLite, das den Fehler "Datenbank ist gesperrt" für eine zweite Abfrage in einer einzigen Transaktion bei Verwendung von Perl DBD :: SQLite liefert? Szenario: Linux, Perl DBI, AutoCommit => 0, eine Subroutine mit zwei Codeblöcken (mit den Blöcken zur Lokalisierung von Variablennamen). Im ersten Codeblock wird ein Abfrage-Handle von prepare() für eine select-Anweisung erstellt, ausgeführt() und der Block geschlossen. Der zweite Codeblock Ein anderer Abfrage-Handle wird erstellt, indem auf eine update-Anweisung vorbereitet wird, und häufig (30% der Zeit) gibt SQLite/DBI zu diesem Zeitpunkt einen Datenbank-gesperrten Fehler. Ich denke, der Fehler passiert während prepare() und nicht während der Ausführung().Warum gibt SQLite eine "Datenbank ist gesperrt" für eine zweite Abfrage in einer Transaktion bei Verwendung von Perls DBD :: SQLite?

Meine Arbeit besteht darin, nach der ersten Abfrage zu committen. (Der Aufruf der ersten Abfrage hat nicht geholfen). Ich ziehe es vor, mich aus mehreren Gründen, die sich auf Eleganz und Leistung beziehen, nicht zu verpflichten. Der ursprüngliche Code hat viele Jahre mit Postgres als Datenbank funktioniert. Ich habe sqlite_use_immediate_transaction ohne Wirkung versucht.

In allen anderen Situationen habe ich festgestellt, dass SQLite sehr gut funktioniert, daher vermute ich, dass dies ein Versehen im DBD-Treiber ist und kein Problem mit SQLite. Leider ist mein aktueller Code ein großer Stapel von Skripten und Modulen, daher habe ich keinen kurzen Testfall für eine einzelne Datei.

+0

Können Sie uns Ihren kleinen Testfall zeigen, der das Problem aufzeigt? –

Antwort

6

Nicht im Zusammenhang damit in jedem ist es: Transaction and Database Locking von der DBD::SQLite perldoc?

Die Transaktion von AutoCommit oder begin_work ist nett und praktisch, aber manchmal kann es zu einem ärgerlichen "Datenbank gesperrt" -Fehler kommen. Dies geschieht normalerweise, wenn jemand eine Transaktion beginnt und versucht, in eine Datenbank zu schreiben, während eine andere Person aus der Datenbank liest (in einer anderen Transaktion). Sie werden überrascht sein, aber SQLite sperrt eine Datenbank nicht, wenn Sie gerade eine normale (verzögerte) Transaktion starten, um die Parallelität zu maximieren. Es reserviert eine Sperre, wenn Sie eine Anweisung zum Schreiben ausgeben, aber bis Sie tatsächlich versuchen, mit einer Commit-Anweisung zu schreiben, können andere Personen aus der Datenbank lesen. Das Lesen aus der Datenbank erfordert jedoch auch eine gemeinsame Sperre, und das verhindert, dass Sie die exklusive Sperre erhalten, die Sie reserviert haben. Daher erhalten Sie den Fehler "Datenbank ist gesperrt" und andere Personen erhalten den gleichen Fehler, wenn sie später versuchen, zu schreiben Sie haben immer noch eine ausstehende Sperre. busy_timeout hilft in diesem Fall nicht.

Um dies zu vermeiden, legen Sie einen Transaktionstyp explizit fest. Sie können eine sofortige Transaktion starten (oder eine exklusive Transaktion beginnen) für jede Transaktion ausführen oder das Datenbankhandleattribut sqlite_use_immediate_transaction auf true (seit 1.30_02) setzen, um immer eine sofortige Transaktion zu verwenden (auch wenn Sie einfach begin_work verwenden oder AutoCommit deaktivieren). .

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

Beachten Sie, dass dies nur funktioniert, wenn alle Verbindungen die gleiche (nicht latent) Transaktion verwenden. Details zum Sperren finden Sie unter http://sqlite.org/lockingv3.html.

Verwandte Themen