sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked
Wie entsperre ich die Datenbank, damit dies funktioniert?
sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked
Wie entsperre ich die Datenbank, damit dies funktioniert?
Antworten:
In Windows können Sie dieses Programm http://www.nirsoft.net/utils/opened_files_view.html ausprobieren, um herauszufinden, ob der Prozess die DB-Datei verarbeitet. Versuchen Sie, das Programm zum Entsperren der Datenbank zu schließen
Unter Linux und MacOS können Sie ähnliche Aktionen ausführen, z. B. wenn Ihre gesperrte Datei development.db lautet:
$ fuser development.db
Dieser Befehl zeigt an, durch welchen Prozess die Datei gesperrt wird:
> development.db: 5430
Töte einfach den Prozess ...
töte -9 5430
... und Ihre Datenbank wird entsperrt.
kill
sollte er in Ordnung sein, aber Sie müssen vorsichtig sein, um ihn richtig zu töten, und er kill -9
ist wahrscheinlich falsch und / oder übertrieben. Wenn der Prozess hängen bleibt und sonst nicht stirbt, brauchen Sie manchmal kill -9
. Sie möchten jedoch nicht den Hauptproduktionsjob beenden, nur damit Sie melden können, dass die Datenbank nicht mehr gesperrt ist!
Ich habe dafür gesorgt, dass meine SQLite-Datenbank durch einen Absturz einer App während eines Schreibvorgangs gesperrt wurde. So habe ich es behoben:
echo ".dump" | sqlite old.db | sqlite new.db
Entnommen aus: http://random.kakaopor.hu/how-to-repair-an-sqlite-database
sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
FOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
Die unten aufgeführte Seite DatabaseIsLocked ist nicht mehr verfügbar. Auf der Seite Dateisperrung und Parallelität werden Änderungen im Zusammenhang mit der in Version 3 eingeführten Dateisperrung beschrieben, die für zukünftige Leser hilfreich sein können. https://www.sqlite.org/lockingv3.html
Die Seite SQLite-Wiki DatabaseIsLocked bietet eine gute Erklärung für diese Fehlermeldung. Zum Teil heißt es, dass die Streitquelle intern ist (für den Prozess, der den Fehler ausgibt).
Auf dieser Seite wird nicht erläutert, wie SQLite entscheidet, dass etwas in Ihrem Prozess gesperrt ist, und welche Bedingungen zu einem falsch positiven Ergebnis führen können.
Das Löschen der -journal-Datei klingt nach einer schrecklichen Idee. Damit kann sqlite die Datenbank nach einem Absturz auf einen konsistenten Zustand zurücksetzen. Wenn Sie es löschen, während sich die Datenbank in einem inkonsistenten Zustand befindet, bleibt eine beschädigte Datenbank übrig. Zitieren einer Seite von der SQLite-Site :
Wenn ein Absturz oder ein Stromausfall auftritt und ein heißes Journal auf der Festplatte verbleibt, müssen die ursprüngliche Datenbankdatei und das heiße Journal mit ihren ursprünglichen Namen auf der Festplatte verbleiben, bis die Datenbankdatei von einem anderen SQLite-Prozess geöffnet und zurückgesetzt wird . [...]
Wir vermuten, dass ein häufiger Fehlermodus für die SQLite-Wiederherstellung folgendermaßen auftritt: Ein Stromausfall tritt auf. Nach Wiederherstellung der Stromversorgung beginnt ein wohlmeinender Benutzer oder Systemadministrator, sich auf der Festplatte nach Schäden umzusehen. Sie sehen ihre Datenbankdatei mit dem Namen "important.data". Diese Datei ist ihnen vielleicht vertraut. Nach dem Absturz gibt es aber auch ein heißes Journal namens "important.data-journal". Der Benutzer löscht dann das Hot Journal und denkt, dass er bei der Bereinigung des Systems hilft. Wir kennen keine andere Möglichkeit, dies zu verhindern, als die Schulung der Benutzer.
Das Rollback soll beim nächsten Öffnen der Datenbank automatisch erfolgen. Es schlägt jedoch fehl, wenn der Prozess die Datenbank nicht sperren kann. Wie andere gesagt haben, ist ein möglicher Grund dafür, dass ein anderer Prozess es derzeit offen hat. Eine andere Möglichkeit ist eine veraltete NFS-Sperre, wenn sich die Datenbank auf einem NFS-Volume befindet. In diesem Fall besteht eine Problemumgehung darin, die Datenbankdatei durch eine neue Kopie zu ersetzen, die nicht auf dem NFS-Server gesperrt ist (mv database.db original.db; cp original.db database.db). Beachten Sie, dass in den häufig gestellten Fragen zu SQLite aufgrund fehlerhafter Implementierungen der NFS-Dateisperrung Vorsicht beim gleichzeitigen Zugriff auf Datenbanken auf NFS-Volumes empfohlen wird.
Ich kann nicht erklären, warum Sie durch das Löschen einer -journal-Datei eine Datenbank sperren können, die Sie vorher nicht konnten. Ist das reproduzierbar?
Das Vorhandensein einer -journal-Datei bedeutet übrigens nicht unbedingt, dass ein Absturz aufgetreten ist oder dass Änderungen rückgängig gemacht werden müssen. Sqlite verfügt über einige verschiedene Journalmodi. Im PERSIST- oder TRUNCATE-Modus bleibt die -journal-Datei immer an Ort und Stelle und ändert den Inhalt, um anzuzeigen, ob Teiltransaktionen zurückgesetzt werden müssen oder nicht.
Wenn Sie den Fehler "Datenbank ist gesperrt" entfernen möchten, gehen Sie folgendermaßen vor:
Wenn ein Prozess eine Sperre für eine SQLite-Datenbank hat und abstürzt, bleibt die Datenbank dauerhaft gesperrt. Das ist das Problem. Es ist nicht so, dass ein anderer Prozess eine Sperre hat.
Die SQLite-Datenbankdateien sind nur Dateien. Der erste Schritt besteht darin, sicherzustellen, dass sie nicht schreibgeschützt sind. Die andere Sache, die Sie tun müssen, ist sicherzustellen, dass Sie keine GUI SQLite DB-Viewer mit geöffneter DB haben. Möglicherweise ist die Datenbank in einer anderen Shell geöffnet, oder in Ihrem Code ist die Datenbank geöffnet. In der Regel wird dies angezeigt, wenn in einem anderen Thread oder einer anderen Anwendung wie SQLite Database Browser die Datenbank zum Schreiben geöffnet ist.
Ich hatte gerade dieses Problem, als ich eine SQLite-Datenbank auf einem Remote-Server verwendete, der auf einem NFS-Mount gespeichert war. SQLite konnte keine Sperre erhalten, nachdem die von mir verwendete Remote-Shell-Sitzung abgestürzt war, während die Datenbank geöffnet war.
Die oben vorgeschlagenen Rezepte für die Wiederherstellung haben bei mir nicht funktioniert (einschließlich der Idee, die Datenbank zuerst zu verschieben und dann zurück zu kopieren). Nach dem Kopieren auf ein Nicht-NFS-System wurde die Datenbank jedoch verwendbar und es scheinen keine Daten verloren gegangen zu sein.
Meine Sperre wurde durch einen Systemabsturz und nicht durch einen Hängevorgang verursacht. Um dies zu beheben, habe ich die Datei einfach umbenannt und dann wieder in den ursprünglichen Namen und Speicherort kopiert.
Mit einer Linux-Shell wäre das ...
mv mydata.db temp.db
cp temp.db mydata.db
Ich habe " Pooling=true
" zur Verbindungszeichenfolge hinzugefügt und es hat funktioniert.
Ich fand die Dokumentation der verschiedenen Sperrzustände in SQLite sehr hilfreich. Michael, wenn Sie Lesevorgänge ausführen können, aber keine Schreibvorgänge in die Datenbank ausführen können, bedeutet dies, dass ein Prozess eine RESERVIERTE Sperre für Ihre Datenbank erhalten hat, den Schreibvorgang jedoch noch nicht ausgeführt hat. Wenn Sie SQLite3 verwenden, gibt es eine neue Sperre namens PENDING, bei der keine Prozesse mehr verbunden werden dürfen, vorhandene Verbindungen jedoch noch Lesevorgänge ausführen können. Wenn dies das Problem ist, sollten Sie sich dies stattdessen ansehen.
Ich habe ein solches Problem in der App, die über zwei Verbindungen auf SQLite zugreift - eine war schreibgeschützt und die zweite zum Schreiben und Lesen. Es sieht so aus, als ob diese schreibgeschützte Verbindung das Schreiben von der zweiten Verbindung blockiert hat. Schließlich stellt sich heraus, dass es erforderlich ist, vorbereitete Anweisungen SOFORT nach der Verwendung abzuschließen oder zumindest zurückzusetzen. Bis zum Öffnen der vorbereiteten Anweisung wurde die für die Datenbank verursachte Schreibblockade blockiert.
VERGESSEN SIE NICHT ANRUFEN:
sqlite_reset(xxx);
oder
sqlite_finalize(xxx);
Einige Funktionen, wie z. B. INDEX, können sehr lange dauern - und die gesamte Datenbank wird gesperrt, während sie ausgeführt wird. In solchen Fällen wird möglicherweise nicht einmal die Journaldatei verwendet!
Der beste / einzige Weg, um zu überprüfen, ob Ihre Datenbank gesperrt ist, weil ein Prozess AKTIV darauf schreibt (und Sie sollten ihn daher verdammt noch mal in Ruhe lassen, bis der Vorgang abgeschlossen ist), besteht darin, die Datei zweimal zu md5 (oder md5sum auf einigen Systemen) . Wenn Sie eine andere Prüfsumme erhalten, wird die Datenbank geschrieben, und Sie möchten diesen Prozess wirklich WIRKLICH nicht beenden, da Sie sonst leicht eine beschädigte Tabelle / Datenbank erhalten können.
Ich werde es noch einmal wiederholen, weil es wichtig ist - die Lösung besteht NICHT darin, das Sperrprogramm zu finden und es zu beenden -, herauszufinden, ob die Datenbank aus gutem Grund über eine Schreibsperre verfügt, und von dort aus fortzufahren. Manchmal ist die richtige Lösung nur eine Kaffeepause.
Der einzige Weg , dieses Locked-but-not-wird-geschrieben zu schaffen Situation ist , wenn Ihr Programm läuft BEGIN EXCLUSIVE
, weil es einige Tabellenänderungen oder so etwas, dann aus irgendeinem Grunde nie sendet eine tun wollte END
danach, und der Prozess wird nie beendet . Es ist höchst unwahrscheinlich, dass alle drei Bedingungen in einem ordnungsgemäß geschriebenen Code erfüllt sind. Wenn also jemand 99 von 100 Mal seinen Sperrprozess beenden möchte, sperrt der Sperrprozess Ihre Datenbank aus gutem Grund. Programmierer fügen die BEGIN EXCLUSIVE
Bedingung normalerweise nicht hinzu , es sei denn, dies ist wirklich erforderlich, da dies die Parallelität verhindert und die Beschwerden der Benutzer erhöht. SQLite selbst fügt es nur hinzu, wenn es wirklich benötigt wird (wie beim Indizieren).
Schließlich existiert der Status "gesperrt" NICHT in der Datei, wie mehrere Antworten angegeben haben - er befindet sich im Kernel des Betriebssystems. Der ausgeführte Prozess BEGIN EXCLUSIVE
hat vom Betriebssystem angefordert, dass die Datei gesperrt wird. Selbst wenn Ihr exklusiver Prozess abgestürzt ist, kann Ihr Betriebssystem herausfinden, ob die Dateisperre beibehalten werden soll oder nicht !! Es ist nicht möglich, eine gesperrte Datenbank zu erhalten, aber kein Prozess sperrt sie aktiv !! Wenn Sie sehen möchten, welcher Prozess die Datei sperrt, ist es normalerweise besser, lsof anstelle von fuser zu verwenden (dies ist eine gute Demonstration des Grundes: /unix/94316/fuser-vs-lsof- zu überprüfende Dateien in Gebrauch ). Wenn Sie über DTrace (OSX) verfügen, können Sie alternativ iosnoop für die Datei verwenden.
Mir ist gerade etwas Ähnliches passiert - meine Webanwendung konnte aus der Datenbank lesen, aber keine Einfügungen oder Aktualisierungen durchführen. Ein Neustart von Apache löste das Problem zumindest vorübergehend.
Es wäre jedoch schön, die Grundursache aufspüren zu können.
Dieser Link löst das Problem. : Wenn Sqlite gibt: Datenbank gesperrt Fehler Es hat mein Problem gelöst, kann für Sie nützlich sein.
Und Sie können die Transaktion beginnen und die Transaktion beenden verwenden, um die Datenbank in Zukunft nicht mehr zu sperren.
Sollte das interne Problem einer Datenbank sein ...
Für mich hat es sich nach dem Versuch, die Datenbank mit "SQLite Manager" zu durchsuchen, manifestiert.
Wenn Sie also keinen anderen Prozess finden, stellen Sie eine Verbindung zur Datenbank her und können ihn einfach nicht beheben. Probieren Sie einfach diese radikale Lösung aus:
rake db:migrate
" ausIch bin auf dasselbe Problem unter Mac OS X 10.5.7 gestoßen, auf dem Python-Skripte von einer Terminalsitzung aus ausgeführt wurden. Obwohl ich die Skripte gestoppt hatte und das Terminalfenster an der Eingabeaufforderung stand, wurde dieser Fehler beim nächsten Ausführen angezeigt. Die Lösung bestand darin, das Terminalfenster zu schließen und dann wieder zu öffnen. Macht für mich keinen Sinn, aber es hat funktioniert.
Ich hatte das gleiche Problem. Anscheinend scheint die Rollback-Funktion die Datenbankdatei mit dem Journal zu überschreiben, das mit der Datenbankdatei identisch ist, jedoch ohne die letzte Änderung. Ich habe dies in meinem Code unten implementiert und es funktioniert seitdem einwandfrei, während mein Code zuvor nur in der Schleife stecken blieb, da die Datenbank gesperrt blieb.
Hoffe das hilft
##############
#### Defs ####
##############
def conn_exec( connection , cursor , cmd_str ):
done = False
try_count = 0.0
while not done:
try:
cursor.execute( cmd_str )
done = True
except sqlite.IntegrityError:
# Ignore this error because it means the item already exists in the database
done = True
except Exception, error:
if try_count%60.0 == 0.0: # print error every minute
print "\t" , "Error executing command" , cmd_str
print "Message:" , error
if try_count%120.0 == 0.0: # if waited for 2 miutes, roll back
print "Forcing Unlock"
connection.rollback()
time.sleep(0.05)
try_count += 0.05
def conn_comit( connection ):
done = False
try_count = 0.0
while not done:
try:
connection.commit()
done = True
except sqlite.IntegrityError:
# Ignore this error because it means the item already exists in the database
done = True
except Exception, error:
if try_count%60.0 == 0.0: # print error every minute
print "\t" , "Error executing command" , cmd_str
print "Message:" , error
if try_count%120.0 == 0.0: # if waited for 2 miutes, roll back
print "Forcing Unlock"
connection.rollback()
time.sleep(0.05)
try_count += 0.05
##################
#### Run Code ####
##################
connection = sqlite.connect( db_path )
cursor = connection.cursor()
# Create tables if database does not exist
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS fix (path TEXT PRIMARY KEY);''')
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS tx (path TEXT PRIMARY KEY);''')
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS completed (fix DATE, tx DATE);''')
conn_comit( connection )
Ein häufiger Grund für diese Ausnahme ist, wenn Sie versuchen, eine Schreiboperation auszuführen, während Sie noch Ressourcen für eine Leseoperation halten. Wenn Sie beispielsweise aus einer Tabelle AUSWÄHLEN und dann versuchen, etwas auszuwählen, das Sie ausgewählt haben, ohne zuerst Ihr ResultSet zu schließen.
Ich hatte auch in einer Multithread-Anwendung den Fehler "Datenbank ist gesperrt", bei dem es sich anscheinend um den SQLITE_BUSY- Ergebniscode handelt, und habe ihn behoben, indem ich sqlite3_busy_timeout auf einen angemessen langen Wert wie 30000 gesetzt habe.
(Nebenbei bemerkt, wie seltsam, dass bei einer 7 Jahre alten Frage niemand dies bereits herausgefunden hat! SQLite ist wirklich ein eigenartiges und erstaunliches Projekt ...)
Bevor Sie die Neustartoption deaktivieren, sollten Sie prüfen, ob Sie den Benutzer der SQLite-Datenbank finden können.
Unter Linux kann man fuser
zu diesem Zweck Folgendes einsetzen :
$ fuser database.db
$ fuser database.db-journal
In meinem Fall erhielt ich folgende Antwort:
philip 3556 4700 0 10:24 pts/3 00:00:01 /usr/bin/python manage.py shell
Was zeigte, dass ich ein anderes Python-Programm mit pid 3556 (manage.py) hatte, das die Datenbank verwendete.
Eine alte Frage mit vielen Antworten. Hier sind die Schritte, die ich kürzlich beim Lesen der obigen Antworten ausgeführt habe. In meinem Fall war das Problem jedoch auf die gemeinsame Nutzung von cifs-Ressourcen zurückzuführen. Dieser Fall wurde bisher nicht gemeldet, also hoffe, er hilft jemandem.
Versuchen Sie, den Sperrmodus für die Verbindungsöffnung mit zu erzwingen
final SQLiteConfig config = new SQLiteConfig();
config.setReadOnly(false);
config.setLockingMode(LockingMode.NORMAL);
connection = DriverManager.getConnection(url, config.toProperties());
Wenn Sie Ihre SQLite-Datenbankdatei über einen freigegebenen NFS-Ordner verwenden, überprüfen Sie diesen Punkt in der SQLite-FAQ und überprüfen Sie die Optionen für die Montagekonfiguration, um sicherzustellen, dass Sie Sperren vermeiden, wie hier beschrieben :
//myserver /mymount cifs username=*****,password=*****,iocharset=utf8,sec=ntlm,file,nolock,file_mode=0700,dir_mode=0700,uid=0500,gid=0500 0 0
Ich habe diesen Fehler in einem Szenario erhalten, das sich von den hier beschriebenen etwas unterscheidet.
Die SQLite-Datenbank befand sich auf einem NFS-Dateisystem, das von drei Servern gemeinsam genutzt wurde. Auf 2 der Server konnte ich erfolgreich Abfragen in der Datenbank ausführen, auf dem dritten dachte ich, ich würde die Meldung "Datenbank ist gesperrt" erhalten.
Die Sache mit dieser 3. Maschine war, dass sie keinen Platz mehr hatte /var
. Jedes Mal, wenn ich versuchte, eine Abfrage in einer beliebigen SQLite-Datenbank in diesem Dateisystem auszuführen, wurde die Meldung "Datenbank ist gesperrt" sowie der folgende Fehler in den Protokollen angezeigt:
8. August 10:33:38 server01 kernel: lockd: 172.22.84.87 kann nicht überwacht werden
Und dieser auch:
8. August 10:33:38 server01 rpc.statd [7430]: Fehler beim Einfügen: Schreiben von /var/lib/nfs/statd/sm/other.server.name.com: Kein Platz mehr auf dem Gerät 8. August 10:33: 38 server01 rpc.statd [7430]: STAT_FAIL an server01 für SM_MON von 172.22.84.87
Nachdem die Weltraumsituation bewältigt war, normalisierte sich alles wieder.
Wenn Sie versuchen, die Chrome-Datenbank zu entsperren , um sie mit SQLite anzuzeigen, fahren Sie Chrome einfach herunter.
Windows
%userprofile%\Local Settings\Application Data\Google\Chrome\User Data\Default\Web Data
or
%userprofile%\Local Settings\Application Data\Google\Chrome\User Data\Default\Chrome Web Data
Mac
~/Library/Application Support/Google/Chrome/Default/Web Data
In Ihren vorherigen Kommentaren haben Sie gesagt, dass eine -journal-Datei vorhanden ist.
Dies kann bedeuten, dass Sie eine (EXKLUSIVE?) Transaktion geöffnet und die Daten noch nicht festgeschrieben haben. Hat Ihr Programm oder ein anderer Prozess das Journal hinter sich gelassen?
Beim Neustart des SQLite-Prozesses wird die Journaldatei überprüft, alle nicht festgeschriebenen Aktionen bereinigt und die -journal-Datei entfernt.
Wie Seun Osewa gesagt hat, wird manchmal ein Zombie-Prozess mit einem erworbenen Schloss im Terminal sitzen, selbst wenn Sie es nicht für möglich halten. Ihr Skript wird ausgeführt, stürzt ab und Sie kehren zur Eingabeaufforderung zurück, aber es gibt einen Zombie-Prozess, der irgendwo durch einen Bibliotheksaufruf ausgelöst wurde, und dieser Prozess hat die Sperre.
Das Schließen des Terminals, in dem Sie sich befanden (unter OSX), funktioniert möglicherweise. Ein Neustart funktioniert. Sie könnten nach "Python" -Prozessen suchen (zum Beispiel), die nichts tun, und sie beenden.
Sie können dies versuchen: .timeout 100
um das Zeitlimit festzulegen. Ich weiß nicht, was in der Befehlszeile passiert, aber in C # .Net, wenn ich das mache: "UPDATE table-name SET column-name = value;"
Ich bekomme, dass die Datenbank gesperrt ist, aber das "UPDATE table-name SET column-name = value"
geht gut.
Es sieht so aus, als würde sqlite beim Hinzufügen nach weiteren Befehlen suchen.