2009-06-30 18 views
15

Jak zapewnić poprawność, gdy wiele procesów uzyskuje dostęp do jednego pliku bazy danych SQLite?SQLite3 i wiele procesów

+0

Przynajmniej mógłbyś oznaczyć swoje pytanie odpowiednim językiem programowania. –

+0

Zbuduj lub określ, że potrzebujesz agnostycznego, agnostycznego, agnostycznego, wszystko-agnostyczne, bez agnostyki. – sharptooth

+1

Chciałbym spróbować ponownie bez "pokaż mi kod" ... –

Odpowiedz

13

Po pierwsze, należy unikać równoczesnego dostępu do plików bazy danych sqlite. Współbieżność jest jednym z słabych punktów sqlite, a jeśli masz bardzo współbieżną aplikację, rozważ użycie innego silnika bazy danych.

Jeśli nie można uniknąć współbieżność lub spadek SQLite, owinąć napisać transakcji BEGIN IMMEDIATE; ... END;. Domyślnym trybem transakcji w sqlite jest DEFERRED, co oznacza, że ​​blokada jest uzyskiwana tylko przy pierwszej faktycznej próbie zapisu. Przy transakcjach IMMEDIATE blokada jest natychmiast pobierana lub natychmiast otrzymujesz SQLITE_BUSY. Gdy ktoś zablokuje bazę danych, inne próby zablokowania będą skutkować SQLITE_BUSY.

Radzenie sobie z SQLITE_BUSY jest czymś, o czym musisz sam zadecydować. W przypadku wielu aplikacji, oczekiwanie na sekundę lub dwie, a następnie ponowna próba działa całkiem dobrze, rezygnacja po n nieudanych próbach. Istnieją pomoce API sqlite3, które ułatwiają to, np. sqlite3_busy_handler() i sqlite3_busy_timeout(), ale można to zrobić również ręcznie.

Można również użyć synchronizacji poziomu OS, aby uzyskać blokadę muteksu w bazie danych, lub użyć przesyłania komunikatów między wątkami/procesami na poziomie systemu operacyjnego w celu zasygnalizowania, kiedy jeden wątek ma dostęp do bazy danych.

+0

Wiem, że należy korzystać z transakcji w ramach jednego procesu. Jednak w mojej sytuacji mam wiele procesów, w przeciwieństwie do wielu wątków, jednocześnie uzyskujących dostęp do tego samego DB. Czy transakcje SQLite naprawdę obsługują taką współbieżność!?!? –

+0

@Tom: Tak, w dolnej warstwie portowania dla systemu operacyjnego sqlite3 istnieje funkcja blokowania działająca w różnych procesach. Zobacz http://www.sqlite.org/lockingv3.html dla więcej – laalto

+1

DEFERRED w rzeczywistości oznacza, że ​​baza danych nie jest (udostępniana) zablokowana, dopóki nie będzie dostępna przez odczyt lub zapis po instrukcji BEGIN (tak, powinna zablokować się na czytać). NATYCHMIAST oznacza, że ​​baza danych jest zablokowana natychmiast po wykonaniu "BEGIN NATYCHMIAST TRANSAKCJI". Zobacz http://www.sqlite.org/lang_transaction.html –

2

Każdy prymityw SQLite zwróci SQLITE_BUSY, jeśli próbuje uzyskać dostęp do bazy danych, do której ma dostęp inny proces w tym samym czasie. Możesz sprawdzić ten kod błędu i po prostu powtórzyć akcję.

Alternatywnie można użyć synchronizacji OS - mutex na MS Windows lub coś podobnego w innych systemach operacyjnych. Proces podejmie próbę pozyskania muteksu, a jeśli ktoś inny go już posiada, proces zostanie zablokowany, dopóki drugi proces nie zakończy operacji i zwolni muteks. Należy zachować ostrożność, aby zapobiec przypadkom, w których proces nabywa muteks, a następnie nigdy go nie zwalnia.

+1

Hmm, czy SQLite nie zapewnia blokad dostępu do bazy danych? –

0

SQLite FAQ o dokładnie this

+1

Przeczytałem to FAQ, zanim opublikowałem tutaj swoje pytanie. Powinienem był to powiedzieć (była to lekcja numer dwa, której nauczyłem się dzisiaj). Nie widziałem dokładnie, co mieli na myśli. Czy mam samemu obsługiwać wszystkie blokady, czy też SQLite ma na to wsparcie? "Kiedy dowolny proces chce napisać, musi zablokować cały plik bazy danych na czas jego aktualizacji, ale zwykle zajmuje to tylko kilka milisekund, inne procesy czekają na pisarza, aby zakończyć, a następnie kontynuować swoją działalność." Wdrożenie tego wymagałoby trochę wysiłku. –

+0

Jest to nie tylko uciążliwe, ale także podatne na błędy. Mam nadzieję, że SQLite będzie wymagało wsparcia, w takim przypadku zastanawiam się, jakie funkcje powinienem użyć. Na marginesie uważam, że dokumentacja SQLite jest nieco zbyt powściągliwa, jeśli chodzi o przykłady z kodem źródłowym ... –

+0

https://meta.stackexchange.com/questions/225370/your-answer-is-in-another- zamek-kiedy-to-odpowiedź-nie-odpowiedź –

2

Zasadniczo trzeba owinąć swój kod dostępu do danych o transakcjach. Pozwoli to zachować spójność danych. Nic więcej nie jest wymagane.

W SQLite używasz

rozpocząć transakcji

dokonać transakcji

pary do oddzielania transakcji. Umieść swój kod SQL pomiędzy, aby go wykonać w pojedynczej transakcji.

Jednak, tak jak poprzedni ludzie komentowali przede mną - należy zwrócić szczególną uwagę na kwestie współbieżności. SQLite może działać dość szybko, jeśli jest używany do odczytu (wiele czytników nie jest blokowanych i może działać jednocześnie).

Jednak - obraz zmienia się znacznie, jeśli kod przeplata zapis i odczyt. Z SQLite - cały plik bazy danych zostanie zablokowany, jeśli aktywny jest nawet pojedynczy program piszący.

Powiązane problemy