it-swarm.com.de

OperationalError: Datenbank ist gesperrt

Ich habe einige wiederholte Operationen in meiner Anwendung ausgeführt (teste sie) und plötzlich bekomme ich einen seltsamen Fehler: 

OperationalError: database is locked

Ich habe den Server neu gestartet, der Fehler bleibt jedoch bestehen. Worum kann es überhaupt gehen?

33
dana

Von Django doc:

SQLite soll ein leichtgewichtiges .__ sein. Datenbank und kann daher keine hohe Parallelität . OperationalError: Datenbank ist gesperrt Fehler zeigen an, dass Ihre Anwendung erfährt mehr Parallelität als sqlite kann standardmäßig mit .__ umgehen. Aufbau. Dieser Fehler bedeutet, dass Ein Thread oder Prozess hat eine exklusive Sperre für die Datenbankverbindung und Bei einem anderen Thread ist das Warten auf .__ abgelaufen. das schloss wird freigegeben.

Der Python-SQLite-Wrapper hat den Standardwert Timeout-Wert, der bestimmt, wie lange Der zweite Thread darf warten auf dem schloss, bevor es ausfällt und löst die OperationalError: Datenbank .__ aus. ist gesperrt.

Wenn Sie diese Fehlermeldung erhalten, können Sie löse es durch:

Wechseln zu einem anderen Datenbank-Backend . Ab einem bestimmten Punkt wird SQLite zu "lite" für reale Anwendungen, und diese Arten von Parallelitätsfehlern zeigen Sie an, dass Sie diesen Punkt erreicht haben.

Schreiben Sie Ihren Code neu, um .__ zu reduzieren. Parallelität und stellen Sie sicher, dass die Datenbank Transaktionen sind von kurzer Dauer.

Erhöhen Sie den Standardwert für das Zeitlimit um Festlegen der Timeout-Datenbankoption Option Option

http://docs.djangoproject.com/de/dev/ref/databases/#database-is-locked-errorsoption

55
patrick

Der praktische Grund dafür ist oft, dass die Python- oder Django-Muscheln eine Anforderung an die Datenbank geöffnet haben und nicht ordnungsgemäß geschlossen wurden. Wenn Sie den Zugriff auf Ihr Terminal abtöten, wird der Zugriff auf das Terminal oft erleichtert. Ich hatte diesen Fehler beim Ausführen von Befehlszeilentests heute. 

Edit: Ich bekomme regelmäßig Upvotes dazu. Wenn Sie den Zugriff beenden möchten, ohne das Terminal neu zu starten, können Sie von der Befehlszeile aus Folgendes tun: 

from Django import db
db.connections.close_all()
21
Withnail

In meinem Fall habe ich die Datenbank vom SQLite Browser aus geöffnet. Wenn ich es über den Browser schließe, ist das Problem behoben.

11
Aminah Nuraini

Wie bereits erwähnt, verwendet ein anderer Prozess die SQLite-Datei und hat die Verbindung nicht geschlossen. Wenn Sie Linux verwenden, können Sie sehen, welche Prozesse die Datei verwenden (zum Beispiel db.sqlite3) Verwenden Sie den Befehl fuser wie folgt:

$ Sudo fuser -v db.sqlite3
                     USER        PID ACCESS COMMAND
/path/to/db.sqlite3:
                     user    955 F.... Apache2

Wenn Sie die Prozesse zum Aufheben der Sperre stoppen möchten, verwenden Sie fuser -k, der das Signal KILL an alle Prozesse sendet, die auf die Datei zugreifen:

Sudo fuser -k db.sqlite3

Beachten Sie, dass dies gefährlich ist, da der Webserverprozess auf einem Produktionsserver möglicherweise gestoppt wird.

Vielen Dank an @ cz-game für den Hinweis auf fuser!

3
mrts

Ich bin auf diese Fehlermeldung in einer Situation gestoßen, die in den Hilfeinformationen, die in Patricks Antwort verlinkt sind, nicht (eindeutig) angesprochen wird.

Wenn ich transaction.atomic() verwende, um einen Aufruf von FooModel.objects.get_or_create() zu beenden und diesen Code gleichzeitig von zwei verschiedenen Threads aus aufzurufen, ist nur ein Thread erfolgreich, während der andere den Fehler "Datenbank ist gesperrt" erhält . Das Ändern der Timeout-Datenbankoption hatte keine Auswirkungen auf das Verhalten.

Ich denke, das liegt an der Tatsache, dass sqlite kann nicht mit mehreren gleichzeitigen Schreibern umgehen , also muss die Anwendung Schreibvorgänge selbst serialisieren.

Ich habe das Problem durch die Verwendung eines threading.RLock - Objekts anstelle von transaction.atomic() gelöst, wenn meine Django App mit einem SQLite-Backend ausgeführt wird Möglicherweise müssen Sie in Ihrer Anwendung etwas anderes tun.

Hier ist mein Code, der FooModel.objects.get_or_create Gleichzeitig in zwei verschiedenen Threads ausführt, falls es hilfreich ist:

from concurrent.futures import ThreadPoolExecutor

import configurations
configurations.setup()

from Django.db import transaction
from submissions.models import ExerciseCollectionSubmission

def makeSubmission(user_id):
    try:
        with transaction.atomic():
            e, _ = ExerciseCollectionSubmission.objects.get_or_create(
                student_id=user_id, exercise_collection_id=172)
    except Exception as e:
        return f'failed: {e}'

    e.delete()

    return 'success'


futures = []

with ThreadPoolExecutor(max_workers=2) as executor:
    futures.append(executor.submit(makeSubmission, 296))
    futures.append(executor.submit(makeSubmission, 297))

for future in futures:
    print(future.result())
1
Evan

Ich habe den gleichen Fehler! Einer der Gründe war, dass die DB-Verbindung nicht geschlossen wurde. Prüfen Sie daher auf nicht geschlossene DB-Verbindungen. Überprüfen Sie auch, ob Sie festgeschrieben den DB haben, bevor Sie die Verbindung schließen.

1
akshika47

Ich stimme der Antwort von @ Patrick nicht zu, die durch das Zitieren dieses Dokuments das Problem von OP (Database is locked) implizit mit diesem verknüpft:

Umschalten auf ein anderes Datenbank-Backend Ab einem gewissen Punkt wird SQLite für reale Anwendungen zu "lite", und diese Art von Parallelitätsfehlern weist darauf hin, dass Sie diesen Punkt erreicht haben.

Dies ist ein bisschen "zu einfach", um SQlite für dieses Problem zu belasten. Wenn Sie nicht über einen sehr ausgelasteten Server mit Tausenden von Verbindungen in derselben Sekunde verfügen, ist der Grund für diesen Database is locked-Fehler wahrscheinlich eher eine schlechte Verwendung der API als ein Problem, das SQlite innewohnt, das "zu leicht" wäre. Hier finden Sie weitere Informationen zu Implementierungsgrenzen für SQLite .


Nun die Lösung:

Ich hatte das gleiche Problem, als ich zwei Skripts verwendete, die dieselbe Datenbank gleichzeitig verwendeten:

  • einer hat mit Schreiboperationen auf die Datenbank zugegriffen
  • der andere hat schreibgeschützt auf die Datenbank zugegriffen

Lösung: tun Sie cursor.close() so bald wie möglich, nachdem Sie eine (auch schreibgeschützte) Abfrage ausgeführt haben.

Hier sind mehr Details .

1
Basj

Für mich wird es gelöst, sobald ich die Django-Shell geschlossen habe, die mit python manage.py Shell geöffnet wurde.

0
Avinash Raj

In meinem Fall hatte ich keine Datenbankoperation gespeichert, die ich im SQLite Browser ausgeführt habe. Das Speichern löste das Problem.

0
Varun Krishna

Dies kann auch passieren, wenn Sie über dbbrowser plugin über pycharm mit Ihrer sqlite-Datenbank verbunden sind. Eine Trennung wird das Problem lösen

0
Nipunu