2010-10-15 31 views
6

Czy jest znany problem z tym, że SQLite daje błąd "baza danych jest zablokowana" dla drugiego zapytania w pojedynczej transakcji podczas korzystania z Perl DBD :: SQLite? Scenariusz: Linux, Perl DBI, AutoCommit => 0, podprogram z dwoma blokami kodu (za pomocą bloków do lokalizowania nazw zmiennych). W pierwszym bloku kodu uchwyt zapytania jest tworzony przez funkcję prepare() w instrukcji select, jest wykonywany() i blok jest zamknięty. Drugi blok kodu inny uchwyt zapytania jest tworzony przez przygotowanie do instrukcji aktualizacji, a często (30% czasu) SQLite/DBI daje błąd bazy danych zablokowany na tym etapie. Myślę, że błąd występuje podczas przygotowywania(), a nie podczas wykonywania().Dlaczego SQLite daje "baza danych jest zablokowana" dla drugiego zapytania w transakcji przy korzystaniu z DBD :: SQLite Perla?

Moja praca polega na zatwierdzeniu po pierwszym zapytaniu. (Zakończenie rozmowy w pierwszym zapytaniu nie pomogło). Wolę nie angażować się z kilku powodów związanych z elegancją i wydajnością. Oryginalny kod sprawdzał się przez wiele lat z Postgres jako bazą danych. Próbowałem sqlite_use_immediate_transaction bez efektu.

We wszystkich innych sytuacjach znalazłem SQLite, który działa bardzo dobrze, więc podejrzewam, że jest to niedopatrzenie w sterowniku DBD, a nie problem z SQLite. Niestety, mój obecny kod jest dużą stertą skryptów i modułów, więc nie mam krótkiego, pojedynczego pliku testowego.

+0

Czy możesz pokazać nam swój mały przypadek testowy, który pokazuje problem? –

Odpowiedz

6

Nie ma to związku w żaden sposób: Transaction and Database Locking z 01ldperldoc?

Transakcja AutoCommit lub begin_work jest dobra i poręczna, ale czasami może pojawić się denerwujący błąd "baza danych jest zablokowana". Zdarza się to zwykle, gdy ktoś rozpoczyna transakcję i próbuje pisać do bazy danych, podczas gdy inna osoba czyta z bazy danych (w innej transakcji). Możesz być zaskoczony, ale SQLite nie blokuje bazy danych, gdy rozpoczynasz zwykłą (odroczoną) transakcję w celu zmaksymalizowania współbieżności. Zastrzega blokadę, kiedy wydajesz instrukcję do zapisu, ale dopóki nie spróbujesz napisać z instrukcją zatwierdzenia, zezwoli ona innym osobom na odczytanie z bazy danych. Jednak odczyt z bazy danych wymaga również współdzielonej blokady, co uniemożliwia użytkownikowi zarezerwowanie wyłącznej blokady, co powoduje błąd "baza danych jest zablokowana", a inne osoby otrzymają ten sam błąd, jeśli spróbują później napisać, ponieważ nadal masz oczekującą blokadę. busy_timeout nie pomaga w tym przypadku.

Aby tego uniknąć, należy jawnie określić typ transakcji. Możesz wydać natychmiastową transakcję (lub rozpocząć transakcję wyłączną) dla każdej transakcji lub ustawić atrybut obsługi sqlite_use_immediate_transaction na true (od 1.30_02), aby zawsze używać natychmiastowej transakcji (nawet jeśli po prostu używasz begin_work lub wyłącza AutoCommit). .

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

Zauważ, że to działa tylko wtedy, gdy wszystkie połączenia używać tego samego (non-odroczony) transakcję. Aby uzyskać szczegóły dotyczące blokowania, patrz http://sqlite.org/lockingv3.html.