Layer 8Ehrlicher Tech-Support

SQLite: WAL-Datenbank auf dem Netzlaufwerk von zwei Rechnern

WAL verlangt alle Prozesse auf demselben Rechner, weil der wal-index im gemeinsamen Speicher liegt. Über ein Netzdateisystem funktioniert das nicht.

Aufwand:
ca. 20 Min.
Voraussetzung:
Die sqlite3-Kommandozeile oder die SQLite-Anbindung der eigenen Anwendung, Schreibzugriff auf das Verzeichnis der Datenbankdatei, Kenntnis darüber, welche Rechner und Prozesse die Datei öffnen
Gilt für:
SQLite laut der Dokumentationsseite Write-Ahead Logging auf sqlite.org, abgerufen am 17.10.2026

Das Symptom

Eine kleine Anwendung mit SQLite-Datenbank läuft seit Jahren auf einem Rechner. Dann wird die Datei auf eine Netzfreigabe gelegt, damit ein zweiter Rechner dieselben Daten sieht. Erst scheint alles zu gehen. Dann fehlen Datensätze, die auf dem einen Rechner eingetragen wurden, auf dem anderen; ein Rechner meldet eine beschädigte Datenbank, der andere arbeitet mit einem Stand von gestern weiter. Neben der Datei liegen zwei Begleiter, datenbank.db-wal und datenbank.db-shm, und niemand weiß, wer sie angelegt hat.

Der Verdacht fällt auf das Netz, auf die Freigabe, auf den zweiten Rechner. Es ist keiner von ihnen allein. Es ist die Kombination.

Die „Layer 8“-Wahrheit

Die Datenbank läuft im WAL-Modus, dem Write-Ahead-Logging, das jemand per PRAGMA journal_mode=WAL eingeschaltet hat, weil Leser und Schreiber sich dann nicht blockieren. Die Dokumentation von SQLite führt dazu eine Liste von Nachteilen, und der erste ist der hier entscheidende: „All processes using a database must be on the same host computer; WAL does not work over a network filesystem.“ Begründung gleich dahinter: WAL verlangt, dass alle Prozesse eine kleine Menge Speicher teilen, und Prozesse auf getrennten Rechnern können offensichtlich keinen Speicher miteinander teilen.

Dieser gemeinsame Speicher ist der wal-index, eine Struktur, mit der Leser schnell finden, welche Seiten im WAL liegen, statt das ganze WAL zu durchsuchen. „The wal-index greatly improves the performance of readers, but the use of shared memory means that all readers must exist on the same machine.“ Umgesetzt ist er als gewöhnliche Datei neben der Datenbank, die -shm-Datei, per mmap eingeblendet. Die Dokumentation beschreibt, warum es ausgerechnet eine Datei im selben Verzeichnis sein muss: Nur so sei zu garantieren, dass alle Prozesse, die auf dieselbe Datenbankdatei zugreifen, denselben gemeinsamen Speicher verwenden. Diese Garantie endet am Rechner. Auf dem Netzlaufwerk sehen beide Rechner dieselbe -shm-Datei, blenden sie aber in zwei getrennte Speicher ein. Jeder hält seinen Index für den einzigen, und beide schreiben in dasselbe WAL. Dass die Daten eine Weile zusammenpassen, ist Glück, kein Beweis. Was getrennte Speicher anrichten, sagt dieselbe Seite an einem verwandten Fall, Prozessen mit verschiedenem Wurzelverzeichnis: Sie sehen verschiedene Dateien und benutzen damit „different shared memory areas, leading to database corruption“.

Es gibt eine Ausnahme, und sie bestätigt die Regel: „Beginning in SQLite version 3.7.4 (2010-12-07), WAL databases can be created, read, and written even if shared memory is unavailable as long as the locking_mode is set to EXCLUSIVE before the first attempted access.“ Dann wird laut Dokumentation nie ein wal-index angelegt, und der eine Prozess darf arbeiten, weil er garantiert allein ist. Die Verbindung bleibt exklusiv, solange der Journal-Modus WAL ist; PRAGMA locking_mode=NORMAL ist in diesem Zustand wirkungslos. Das hilft einem Dienst, der seine Datei besitzt. Es hilft nicht zwei Rechnern, die sich eine teilen wollen, denn genau das Teilen schließt es aus.

Die ehrliche Antwort ist unbequem: SQLite ist für eine Datei auf einem Rechner gebaut. Wer dieselben Daten von mehreren Rechnern aus schreiben will, braucht einen Prozess, der die Datei allein besitzt und die anderen über das Netz bedient, oder einen Datenbankserver, der genau dafür gemacht ist. Die Freigabe war nie die Lösung. Sie war nur die Stelle, an der der Fehler sichtbar wurde.

Die echte, verifizierte Lösung

1000 % faktenbasiert. Jeder Befehl ist real, jeder Pfad existiert. Schritt für Schritt:

  1. 1.

    Journal-Modus und Speicherort der Datei feststellen

    PRAGMA journal_mode liefert den aktuellen Modus. Liegt die Datei auf einem eingebundenen Netzdateisystem, zeigt das mount-Kommando den Typ, etwa nfs oder cifs. Beides zusammen ist die Diagnose: WAL plus Netzdateisystem plus mehr als ein Rechner ist genau die Kombination, die die Dokumentation ausschließt. Liegen daneben Dateien mit den Endungen -wal und -shm, ist der WAL-Modus aktiv, auch wenn sich niemand erinnert, ihn gesetzt zu haben; der Schalter kann auch in der Anwendung oder ihrer Bibliothek stehen.

    sqlite3 /pfad/zur/datenbank.db 'PRAGMA journal_mode;'
    mount | grep -E 'nfs|cifs|smb'
    ls -l /pfad/zur/datenbank.db*
    
  2. 2.

    Entscheiden: ein Rechner pro Datenbank

    Die Dokumentation lässt keinen Spielraum: Alle Prozesse, die eine WAL-Datenbank nutzen, müssen auf demselben Rechner laufen. Also entweder die Datenbank auf einen lokalen Datenträger des einen Rechners legen, der sie benutzt, und den anderen Rechner über einen Dienst auf diesem Rechner zugreifen lassen, oder den Netzwerkzugriff ganz aufgeben. Ein Umbenennen der Datei, ein anderes Netzprotokoll oder bessere Hardware ändern an der Ursache nichts, weil gemeinsamer Speicher über Rechnergrenzen hinweg nicht existiert.

  3. 3.

    Wenn nur ein Prozess zugreift: locking_mode EXCLUSIVE vor dem ersten Zugriff

    Ist garantiert nur ein einziger Prozess an der Datei, kann WAL ohne gemeinsamen Speicher betrieben werden, indem locking_mode vor dem ersten Zugriff im WAL-Modus auf EXCLUSIVE gesetzt wird. Laut Dokumentation wird dann nie ein wal-index im gemeinsamen Speicher angelegt. Die Verbindung bleibt exklusiv, solange der Journal-Modus WAL ist, und andere Prozesse werden ausgesperrt, auch solche auf demselben Rechner. Das ist eine Lösung für einen Dienst, der seine Datenbank allein besitzt, nicht für die geteilte Datei.

    PRAGMA locking_mode=EXCLUSIVE;
    PRAGMA journal_mode=WAL;
    
  4. 4.

    Sonst den Journal-Modus zurückstellen und die Daten prüfen

    Wird die Datei weiter von mehreren Rechnern geöffnet und soll SQLite bleiben, dann ohne WAL. PRAGMA journal_mode=DELETE schaltet in den Rollback-Journal-Modus zurück; das geht nur, wenn keine andere Verbindung die Datenbank gerade offen hält. Vorher die Datenbank mit PRAGMA integrity_check prüfen und eine Sicherung anlegen, denn nach einem Betrieb, den die Dokumentation ausdrücklich ausschließt, ist der Zustand der Datei nicht verlässlich. Und die eigentliche Lösung, ein Datenbankserver für mehrere Rechner, bleibt auf dem Tisch.

    sqlite3 /pfad/zur/datenbank.db 'PRAGMA integrity_check;'
    cp /pfad/zur/datenbank.db /pfad/zur/datenbank.sicherung.db
    sqlite3 /pfad/zur/datenbank.db 'PRAGMA journal_mode=DELETE;'
    

Häufige Fragen (FAQ)

?Warum darf eine WAL-Datenbank nicht von zwei Rechnern gleichzeitig benutzt werden?

Weil der Mechanismus gemeinsamen Speicher voraussetzt. Die Dokumentation zählt es unter den Nachteilen des WAL-Modus auf: „All processes using a database must be on the same host computer; WAL does not work over a network filesystem.“ Und sie erklärt auch, warum: Dies sei so, weil WAL verlange, dass alle Prozesse eine kleine Menge Speicher teilen, und Prozesse auf getrennten Rechnern könnten offensichtlich keinen Speicher miteinander teilen. Die Datei auf dem Netzlaufwerk ist für beide Rechner sichtbar, der gemeinsame Speicher nicht. Jeder Rechner hat seinen eigenen Blick auf den Stand der Datenbank, und die beiden Blicke stimmen nicht überein.

?Was ist der wal-index und wo liegt er?

Eine Hilfsstruktur, die Lesern sagt, welche Seiten im WAL liegen, ohne das ganze WAL zu durchsuchen. Die Dokumentation: „The wal-index greatly improves the performance of readers, but the use of shared memory means that all readers must exist on the same machine.“ Umgesetzt ist der gemeinsame Speicher laut Dokumentation als gewöhnliche Datei neben der Datenbank mit der Endung -shm, die per mmap eingeblendet wird. Die Entwickler begründen das: Nur so sei zu garantieren, dass alle Prozesse, die auf dieselbe Datenbankdatei zugreifen, denselben gemeinsamen Speicher verwenden. Diese Garantie gilt innerhalb eines Rechners. Über ein Netzdateisystem ist die -shm-Datei zwar sichtbar, aber das Einblenden in den Speicher zweier Rechner ergibt zwei getrennte Speicherbereiche.

?Gibt es einen Weg, WAL ohne gemeinsamen Speicher zu nutzen?

Ja, aber nur für genau einen Prozess. Die Dokumentation: „Beginning in SQLite version 3.7.4 (2010-12-07), WAL databases can be created, read, and written even if shared memory is unavailable as long as the locking_mode is set to EXCLUSIVE before the first attempted access.“ Ein Prozess kann dann ohne gemeinsamen Speicher arbeiten, wenn er garantiert der einzige ist, der die Datenbank öffnet. Die Verbindung bleibt laut Dokumentation im EXCLUSIVE-Modus, solange der Journal-Modus WAL ist; ein Zurückschalten mit PRAGMA locking_mode=NORMAL ist wirkungslos, erst der Wechsel aus dem WAL-Modus heraus hebt die exklusive Sperre auf. Das löst das Problem der zwei Rechner nicht, es macht nur den einen Rechner sauber.

?Ist der Rollback-Journal-Modus auf dem Netzlaufwerk dann die Lösung?

Er hat die Einschränkung mit dem gemeinsamen Speicher nicht, denn die stammt aus dem wal-index. Ob die Sperren des Netzdateisystems selbst zuverlässig sind, ist eine andere Frage, die diese Dokumentationsseite nicht beantwortet; sie behandelt nur, warum WAL dort nicht funktioniert. Wer eine Datenbank von mehreren Rechnern gleichzeitig beschreiben will, hat mit SQLite das falsche Werkzeug gewählt, unabhängig vom Journal-Modus. Ein Datenbankserver, der die Zugriffe über das Netz koordiniert, ist dafür gebaut. SQLite ist für eine Datei auf einem Rechner gebaut.

Belege

Diese Seite ist gegen die folgenden Primärquellen geprüft – Hersteller, Standard oder Gesetzestext. Wer es nicht glaubt, muss es nicht: Da steht, wo es nachzulesen ist.

Zuletzt geprüft am . Dokumentation altert – ein Datum daneben ist der einzige ehrliche Umgang damit.

Auch zu finden unter

Verwandte Fehler

SWLästigdatabase is locked

SQLite: database is locked

SQLite meldet „database is locked“? Sie erlaubt nur einen Schreiber — ein hängender Zugriff oder ein Netzlaufwerk bringt sie ins Stocken.

SWLästigAccess denied for user

MySQL: Access denied for user

Der Login wird abgewiesen, obwohl das Passwort stimmt? Bei MySQL zählt auch, von welchem Host aus man kommt — der Benutzer ist an eine Herkunft gebunden.