Aus dem Django-Dokument:
SQLite ist als kompakte Datenbank gedacht und kann daher kein hohes Maß an Parallelität unterstützen. OperationalError: Datenbank ist gesperrt Fehler weisen darauf hin, dass in Ihrer Anwendung mehr Parallelität auftritt, als SQLite in der Standardkonfiguration verarbeiten kann. Dieser Fehler bedeutet, dass ein Thread oder Prozess eine exklusive Sperre für die Datenbankverbindung hat und ein anderer Thread eine Zeitüberschreitung aufweist, die darauf wartet, dass die Sperre aufgehoben wird.
Der SQLite-Wrapper von Python verfügt über einen Standardwert für das Zeitlimit, der bestimmt, wie lange der zweite Thread auf die Sperre warten darf, bevor das Zeitlimit überschritten wird, und den Fehler OperationalError: database is gesperrt auslöst.
Wenn Sie diesen Fehler erhalten, können Sie ihn beheben durch:
- Wechseln zu einem anderen Datenbank-Backend. Ab einem bestimmten Punkt wird SQLite für reale Anwendungen zu "lite", und diese Art von Parallelitätsfehlern zeigen an, dass Sie diesen Punkt erreicht haben.
- Schreiben Sie Ihren Code neu, um die Parallelität zu verringern und sicherzustellen, dass Datenbanktransaktionen nur von kurzer Dauer sind.
- Erhöhen Sie den Standardwert für das Zeitlimit, indem Sie die Option für die Zeitlimitdatenbank festlegen
http://docs.djangoproject.com/de/dev/ref/databases/#database-is-locked-errorsoption
create_engine('sqlite:///{}'.format(xxx), connect_args={'timeout': 15})
In meinem Fall lag es daran, dass ich die Datenbank über den SQLite-Browser öffne. Wenn ich es über den Browser schließe, ist das Problem behoben.
quelle
Der praktische Grund dafür ist häufig, dass die Python- oder Django-Shells eine Anfrage an die DB geöffnet haben und diese nicht ordnungsgemäß geschlossen wurde. Wenn Sie Ihren Terminalzugriff beenden, wird er häufig freigegeben. 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 über die Befehlszeile Folgendes tun:
from django import db db.connections.close_all()
quelle
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<subfolder_with_setings.json>.settings")
Ansonsten IMHO beste Antwort hierdb.connections.close_all()
Tipp. Ich suchte nach etwas, das die Datenbank entsperren würde, bevor ich ein Bereinigungsskript einschaltetearDown()
. Dies hat es behoben. Vielen Dank.from django.conf import settings settings.configure()
von hier aus laufen .Ich bin mit der Antwort von @ Patrick nicht einverstanden, die durch das Zitieren dieses Dokuments implizit das Problem (
Database is locked
) von OP damit verknüpft :Dies ist ein bisschen "zu einfach", um SQlite für dieses Problem zu belasten (das bei korrekter Verwendung sehr leistungsfähig ist ; es ist nicht nur ein Spielzeug für kleine Datenbanken, lustige Tatsache :)
An SQLite database is limited in size to 140 terabytes
.Wenn Sie keinen sehr ausgelasteten Server mit Tausenden von Verbindungen in derselben Sekunde haben, ist der Grund für diesen
Database is locked
Fehler wahrscheinlich eher eine schlechte Verwendung der API als ein Problem, das SQlite innewohnt und "zu leicht" wäre . Hier finden Sie weitere Informationen zu Implementierungsbeschränkungen für SQLite .Nun die Lösung:
Ich hatte das gleiche Problem, als ich zwei Skripte gleichzeitig mit derselben Datenbank verwendete:
Lösung: Führen Sie
cursor.close()
nach einer (sogar schreibgeschützten) Abfrage immer so bald wie möglich eine Aktion durch.Hier finden Sie weitere Details .
quelle
Wie andere bereits gesagt haben, gibt es einen anderen Prozess, der die SQLite-Datei verwendet und die Verbindung nicht geschlossen hat. Wenn Sie Linux verwenden, können Sie
db.sqlite3
mit dem folgendenfuser
Befehl sehen, welche Prozesse die Datei (zum Beispiel ) verwenden :Wenn Sie die Prozesse stoppen möchten, um die Sperre aufzuheben, verwenden Sie
fuser -k
diese Option, um dasKILL
Signal an alle Prozesse zu senden, die auf die Datei zugreifen:sudo fuser -k db.sqlite3
Beachten Sie, dass dies gefährlich ist, da dies den Webserverprozess auf einem Produktionsserver stoppen kann.
Vielen Dank an @ cz-game für den Hinweis
fuser
!quelle
sudo fuser -k app.db
in meinem FallIch bin auf diese Fehlermeldung in einer Situation gestoßen, die in den Hilfeinformationen in Patricks Antwort nicht (eindeutig) angesprochen wird.
Wenn ich
transaction.atomic()
einen Aufruf anFooModel.objects.get_or_create()
diesen Code verpackte und ihn gleichzeitig von zwei verschiedenen Threads aus aufrief, war nur ein Thread erfolgreich, während der andere den Fehler "Datenbank ist gesperrt" erhielt. Das Ändern der Timeout-Datenbankoption hatte keine Auswirkungen auf das Verhalten.Ich denke, dies liegt an der Tatsache, dass SQLite nicht mehrere gleichzeitige Writer verarbeiten kann , sodass die Anwendung Schreibvorgänge selbst serialisieren muss.
Ich habe das Problem gelöst, indem ich ein
threading.RLock
Objekt verwendet habe, anstatttransaction.atomic()
wenn meine Django-App mit einem SQLite-Backend ausgeführt wird. Das ist nicht ganz gleichwertig, daher müssen Sie möglicherweise etwas anderes in Ihrer Anwendung tun.Hier ist mein Code, der
FooModel.objects.get_or_create
gleichzeitig von zwei verschiedenen Threads ausgeführt wird, 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())
quelle
Dies kann auch passieren, wenn Sie über das DBBrowser-Plugin über Pycharm mit Ihrer SQLite-Datenbank verbunden sind. Das Trennen der Verbindung löst das Problem
quelle
Für mich wird es gelöst, sobald ich die Django-Shell geschlossen habe, die mit geöffnet wurde
python manage.py shell
quelle
Ich habe den gleichen Fehler! Einer der Gründe war, dass die DB-Verbindung nicht geschlossen wurde. Suchen Sie daher nach nicht geschlossenen DB-Verbindungen . Überprüfen Sie außerdem, ob Sie die Datenbank festgeschrieben haben , bevor Sie die Verbindung schließen.
quelle
Ich hatte einen ähnlichen Fehler direkt nach der ersten Instanziierung von Django (v3.0.3). Alle Empfehlungen hier funktionierten nicht außer:
db.sqlite3
Datei und verlor die Daten dort, falls vorhanden,python manage.py makemigrations
python manage.py migrate
Übrigens, wenn Sie nur PostgreSQL testen möchten:
Ändern Sie das
settings.py
, um dies hinzuzufügenDATABASES
:DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'myproject', 'USER': 'postgres', 'PASSWORD': 'mypassword', 'HOST': 'localhost', 'PORT': '5432', } }
... und Datenbankadapter hinzufügen:
pip install psycopg2-binary
Dann das Übliche:
python manage.py makemigrations python manage.py migrate
quelle
In meinem Fall hatte ich keine Datenbankoperation gespeichert, die ich im SQLite-Browser ausgeführt hatte. Durch Speichern wurde das Problem behoben.
quelle
Ein sehr ungewöhnliches Szenario, das mir passiert ist.
Es gab eine unendliche Rekursion, die die Objekte immer wieder schuf.
Insbesondere habe ich mit DRF die Erstellungsmethode in einer Ansicht überschrieben, und das habe ich getan
def create(self, request, *args, **kwargs): .... .... return self.create(request, *args, **kwargs)
quelle
Schließen Sie einfach die Datenbank (stoppen Sie sie) und öffnen Sie sie (starten Sie sie). Dies löste mein Problem.
quelle
Hier sind bereits viele Antworten verfügbar, auch wenn ich meinen Fall teilen möchte, kann dies jemandem helfen.
Ich habe die Verbindung in der Python-API geöffnet, um Werte zu aktualisieren. Die Verbindung wird erst nach Erhalt der Serverantwort geschlossen. Hier habe ich die Verbindung geöffnet, um eine andere Operation auf dem Server auszuführen, bevor ich die Verbindung in der Python-API geschlossen habe.
quelle
Wenn Sie diesen Fehler während der Verwendung erhalten
manage.py shell
, ist ein möglicher Grund, dass auf einem Entwicklungsserver (manage.py runserver
) die Datenbank gesperrt ist. Das Stoppen des Servers während der Verwendung der Shell hat das Problem für mich immer behoben.quelle
Ich fand, dass dies für meine Bedürfnisse funktionierte. (Thread-Sperre) YMMV conn = sqlite3.connect (Datenbank, Timeout = 10)
https://docs.python.org/3/library/sqlite3.html
sqlite3.connect (Datenbank [, Zeitüberschreitung, Erkennungstypen, Isolationsstufe, Prüfname, Factory, zwischengespeicherte Anweisungen, URL])
Wenn auf eine Datenbank über mehrere Verbindungen zugegriffen wird und einer der Prozesse die Datenbank ändert, wird die SQLite-Datenbank gesperrt, bis diese Transaktion festgeschrieben wird. Der Parameter timeout gibt an, wie lange die Verbindung warten soll, bis die Sperre aufgehoben wird, bis eine Ausnahme ausgelöst wird. Der Standardwert für den Timeout-Parameter ist 5.0 (fünf Sekunden).
quelle
UPDATE django Version 2.1.7
Ich habe diesen Fehler
sqlite3.OperationalError: database is locked
mitpytest
mitdjango
.Lösung:
Wenn wir
@pytest.mark.django_db
Dekorateur verwenden. Es wird einin-memory-db
Test erstellt.Benannt:
file:memorydb_default?mode=memory&cache=shared
Wir können diesen Namen bekommen mit:from django.db import connection db_path = connection.settings_dict['NAME']
Gehen Sie wie folgt vor, um auf diese Datenbank zuzugreifen und sie auch zu bearbeiten:
Stellen Sie eine Verbindung zur Datenbank her:
with sqlite3.connect(db_path, uri=True) as conn: c = conn.cursor()
Verwenden Sie
uri=True
diese Option, um die Datenträgerdatei anzugeben, die die zu öffnende SQLite-Datenbank ist.Um den Fehler zu vermeiden, aktivieren Sie Transaktionen im Dekorator:
@pytest.mark.django_db(transaction=True)
Letzte Funktion:
from django.db import connection @pytest.mark.django_db(transaction=True) def test_mytest(): db_path = connection.settings_dict['NAME'] with sqlite3.connect(db_path, uri=True) as conn: c = conn.cursor() c.execute('my amazing query') conn.commit() assert ... == ....
quelle
pytest
und ich nicht weiß, waspytest.mark.django_db
tut. In den SQLite-Dokumenten wird nicht angegeben, dass für speicherinterne Datenbanken unterschiedliche Einschränkungen für die Parallelität gelten.Starten Sie einfach Ihren Server neu, um alle aktuellen Prozesse zu löschen, bei denen Ihre Datenbank gesperrt ist.
quelle
Versuchen Sie diesen Befehl:
sudo fuser -k 8000/tcp
quelle