2009-06-30 13 views
15

Wie sollte man die Korrektheit sicherstellen, wenn mehrere Prozesse auf eine einzelne SQLite-Datenbankdatei zugreifen?SQLite3 und mehrere Prozesse

+0

Zumindest könnten Sie Ihre Frage mit der entsprechenden Programmiersprache markiert haben. –

+0

Yeap, oder geben Sie an, dass Sie einen sprachunabhängigen plattformunabhängigen, alles-agnostischen Ansatz benötigen. – sharptooth

+1

Ich würde versuchen, erneut zu fragen, ohne "mir den Code anzeigen" ... –

Antwort

13

Vermeiden Sie zunächst den gleichzeitigen Zugriff auf SQLite-Datenbankdateien. Parallelität ist einer der Schwachpunkte von SQLite. Wenn Sie eine sehr gleichzeitige Anwendung haben, sollten Sie eine andere Datenbank-Engine verwenden.

Wenn Sie nicht Gleichzeitigkeit vermeiden können oder SQLite fallen, wickeln Sie Ihre Schreib Transaktionen in BEGIN IMMEDIATE; ... END;. Der Standardtransaktionsmodus in sqlite ist DEFERRED, was bedeutet, dass eine Sperre nur beim ersten tatsächlichen Schreibversuch erfasst wird. Mit IMMEDIATE Transaktionen wird das Schloss sofort erworben, oder Sie erhalten sofort SQLITE_BUSY. Wenn jemand eine Sperre für die Datenbank hält, führen andere Sperrversuche zu SQLITE_BUSY.

Der Umgang mit SQLITE_BUSY ist etwas, das Sie für sich selbst entscheiden müssen. Bei vielen Anwendungen funktioniert das Warten auf ein oder zwei Sekunden und dann ein erneuter Versuch ganz in Ordnung, nach n fehlgeschlagenen Versuchen aufzugeben. Es gibt sqlite3 API-Helfer, die das einfach machen, z. sqlite3_busy_handler() und sqlite3_busy_timeout() aber es kann auch manuell gemacht werden.

Sie können auch die Synchronisierung auf Betriebssystemebene verwenden, um eine Mutex-Sperre für die Datenbank zu erhalten, oder die Inter-Thread-/Interprozess-Messaging auf Betriebssystemebene verwenden, um zu signalisieren, wann ein Thread auf die Datenbank zugreift.

+0

Ich weiß, dass man Transaktionen innerhalb eines Prozesses verwenden muss. Meine Situation besteht jedoch darin, dass ich im Gegensatz zu mehreren Threads mehrere Prozesse gleichzeitig auf dieselbe Datenbank zugreife. Bewerkstelligen SQLite-Transaktionen diese Parallelität?!? –

+0

@Tom: Ja, in der sqlite3 OS-spezifischen Portierungsschicht gibt es Funktionen zum Sperren, die über Prozesse hinweg funktionieren. Siehe http://www.sqlite.org/lockingv3.html für mehr – laalto

+1

DEFERRED bedeutet eigentlich, dass die Datenbank nicht (shared) gesperrt ist, bis sie entweder durch Lesen oder Schreiben nach der BEGIN-Anweisung aufgerufen wird (ja, sie sollte auf der lesen). IMMEDIATE bedeutet, dass die Datenbank unmittelbar nach dem Ausführen von "BEGIN SOFORTÜBERTRAGUNG" gesperrt wird. Siehe http://www.sqlite.org/lang_transaction.html –

2

Jedes SQLite-Grundelement gibt SQLITE_BUSY zurück, wenn es versucht, auf eine Datenbank zuzugreifen, auf die ein anderer Prozess zur gleichen Zeit zugreift. Sie könnten nach diesem Fehlercode suchen und die Aktion einfach wiederholen.

Alternativ können Sie OS-Synchronisation - Mutex auf MS Windows oder etwas ähnliches auf anderen Betriebssystemen verwenden. Der Prozess wird versuchen, den Mutex zu übernehmen, und wenn jemand anders ihn bereits hält, wird der Prozess blockiert, bis der andere Prozess die Operation beendet und den Mutex freigibt. Es sollte sorgfältig darauf geachtet werden, Fälle zu vermeiden, in denen der Prozess den Mutext erwirbt und ihn dann nie freigibt.

+1

Hmm, bietet SQLite keine Sperren zum Schutz des Zugriffs auf die Datenbankdatei? –

0

Die SQLite FAQ über genau this

+1

Ich habe diese FAQ gelesen, bevor ich meine Frage hier gepostet habe. Ich hätte das natürlich sagen sollen (das war Lektion Nummer zwei, die ich heute gelernt habe). Ich konnte nicht genau sehen, was sie meinten. Soll ich selbst alle Locking-Sachen behandeln, oder hat SQLite dafür Unterstützung? "Wenn ein Prozess schreiben möchte, muss er die gesamte Datenbankdatei für die Dauer der Aktualisierung sperren. Aber das dauert normalerweise nur ein paar Millisekunden. Andere Prozesse warten nur darauf, dass der Schreiber fertig ist und dann weiter." Es würde einige Anstrengungen erfordern, um dies für mich umzusetzen. –

+0

Es ist nicht nur langweilig, es ist auch fehleranfällig. Und ich hoffe, dass SQLite die nötige Unterstützung hat. In diesem Fall frage ich mich, welche Funktionen ich verwenden soll. Als Nebenbemerkung denke ich, dass die Dokumentation von SQLite etwas zu zurückhaltend ist, wenn es um Beispiele mit Quellcode geht ... –

+0

https://meta.stackexchange.com/questions/225370/your-answer-is-in-an-other- Schloss-wenn-ist-eine-Antwort-nicht-eine-Antwort –

2

Grundsätzlich müssen Sie Ihren Datenzugriffscode mit den Transaktionen wickeln. Dies wird Ihre Daten konsistent halten. Nichts anderes ist erforderlich.

In SQLite verwenden Sie

BEGIN TRANSACTION

COMMIT TRANSACTION

Paare Ihre Transaktionen zu begrenzen. Setzen Sie Ihren SQL-Code dazwischen, damit er in einer einzigen Transaktion ausgeführt werden kann.

Allerdings, wie vorherige Leute vor mir kommentiert haben - Sie müssen aufmerksam auf Nebenläufigkeit Probleme achten. SQLite kann ziemlich schnell arbeiten, wenn es für den Lesezugriff verwendet wird (mehrere Leser sind nicht blockiert und können gleichzeitig ausgeführt werden).

Allerdings - das Bild ändert sich erheblich, wenn Ihr Code Schreib- und Lesezugriff verschachtelt. Mit SQLite - Ihre gesamte Datenbankdatei wird gesperrt, wenn auch nur ein einziger Writer aktiv ist.