sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked
Comment puis-je déverrouiller la base de données pour que cela fonctionne?
Dans Windows, vous pouvez essayer ce programme http://www.nirsoft.net/utils/opened_files_view.html pour savoir si le processus gère le fichier db. Essayez fermé ce programme pour déverrouiller la base de données
Sous Linux et macOS, vous pouvez faire quelque chose de similaire, par exemple, si votre fichier verrouillé est development.db:
$ fuser development.db
Cette commande montrera quel processus verrouille le fichier:
> development.db: 5430
Tuez le processus ...
tuer -9 5430
... et votre base de données sera déverrouillée.
J'ai bloqué ma base de données sqlite en bloquant une application pendant une écriture. Voici comment je l'ai corrigé:
echo ".dump" | sqlite old.db | sqlite new.db
Tiré de: http://random.kakaopor.hu/how-to-repair-an-sqlite-database
Le wiki SQLite DatabaseIsLocked offre une bonne explication de ce message d'erreur. Il indique en partie que la source de conflit est interne (au processus émettant l'erreur).
Ce que cette page n'explique pas, c'est comment SQLite décide qu'un élément de votre processus est verrouillé et quelles conditions peuvent conduire à un faux positif.
Supprimer le fichier journal est une idée terrible. Il permet à sqlite de rétablir la cohérence de la base de données après un crash. Si vous la supprimez alors que la base de données est dans un état incohérent, vous vous retrouvez avec une base de données corrompue. Citer une page du site sqlite :
Si un crash ou une panne de courant se produit et qu'un journal dynamique reste sur le disque, il est essentiel que le fichier de base de données d'origine et le journal actif restent sur le disque avec leurs noms d'origine jusqu'à ce que le fichier de base de données soit ouvert par un autre processus SQLite et restauré. . [...]
Nous pensons qu'un mode de défaillance commun pour la récupération SQLite se produit comme suit: Une panne de courant se produit. Une fois le courant rétabli, un utilisateur bien intentionné ou un administrateur système commence à rechercher des dommages sur le disque. Ils voient leur fichier de base de données nommé "important.data". Ce dossier leur est peut-être familier. Mais après le crash, il existe également un journal à chaud appelé "important.data-journal". L'utilisateur supprime ensuite le journal actif en pensant qu'il aide à nettoyer le système. Nous ne connaissons aucun moyen d'empêcher cela autre que la formation des utilisateurs.
La restauration est supposée se produire automatiquement à la prochaine ouverture de la base de données, mais elle échouera si le processus ne peut pas verrouiller la base de données. Comme d'autres l'ont dit, une des raisons possibles est qu'un autre processus est actuellement ouvert. Une autre possibilité est un verrou NFS périmé, si la base de données se trouve sur un volume NFS. Dans ce cas, une solution de contournement consiste à remplacer le fichier de base de données par une nouvelle copie non verrouillée sur le serveur NFS (mv database.db original.db; cp original.db database.db). Notez que la sqlite FAQ recommande de prendre des précautions concernant l’accès simultané aux bases de données sur les volumes NFS, en raison de l’implémentation erronée du verrouillage de fichier NFS.
Je ne peux pas expliquer pourquoi la suppression d'un fichier journal vous permettrait de verrouiller une base de données que vous ne pouviez pas auparavant. Est-ce reproductible?
En passant, la présence d'un fichier journal ne signifie pas nécessairement qu'il y a eu un crash ou que des modifications doivent être annulées. Sqlite a plusieurs modes de journal différents et, dans les modes PERSIST ou TRUNCATE, laisse le fichier journal toujours en place et modifie le contenu pour indiquer s’il existe ou non des transactions partielles à annuler.
Si un processus verrouille une base de données SQLite et se bloque, la base de données reste verrouillée en permanence. C'est le problème. Ce n'est pas qu'un autre processus a un verrou.
Si vous souhaitez supprimer une erreur "la base de données est verrouillée", procédez comme suit:
les fichiers de base de données SQLite ne sont que des fichiers, la première étape consiste donc à s’assurer qu’il n’est pas en lecture seule. L'autre chose à faire est de vous assurer que vous n'avez pas une sorte de visualiseur de base de données GUI SQLite DB avec la base de données ouverte. Vous pourriez avoir la base de données ouverte dans un autre shell ou votre code peut avoir la base de données ouverte. En règle générale, vous verriez ceci si un autre thread, ou une application telle que SQLite Database Browser, ouvre la base de données en écriture.
J'ai eu ce problème tout à l'heure, en utilisant une base de données SQLite sur un serveur distant, stocké sur un montage NFS. SQLite n'a pas pu obtenir de verrouillage après la fermeture de la session Shell distante que j'ai utilisée alors que la base de données était ouverte.
Les recettes de récupération suggérées ci-dessus ne fonctionnaient pas pour moi (y compris l'idée de déplacer d'abord, puis de copier la base de données). Mais après l'avoir copiée sur un système autre que NFS, la base de données est devenue utilisable et aucune donnée ne semble avoir été perdue.
Mon verrouillage a été provoqué par une panne du système et non par un processus suspendu. Pour résoudre ce problème, j'ai simplement renommé le fichier, puis je l'ai recopié dans son nom et son emplacement d'origine.
En utilisant un shell Linux qui serait ...
mv mydata.db temp.db
cp temp.db mydata.db
J'ai trouvé très utile la documentation des différents états de verrouillage dans SQLite. Michael, si vous pouvez effectuer des lectures mais pas effectuer des écritures dans la base de données, cela signifie qu'un processus a obtenu un verrou RÉSERVÉ sur votre base de données mais qu'il n'a pas encore exécuté l'écriture. Si vous utilisez SQLite3, il existe un nouveau verrou appelé PENDING dans lequel plus aucun processus n'est autorisé à se connecter mais où les connexions existantes peuvent encore effectuer des lectures. Par conséquent, si c'est le problème, vous devriez plutôt l'examiner.
J'ai ajouté "Pooling=true
" à la chaîne de connexion et cela a fonctionné.
Cette erreur peut être levée si le fichier se trouve dans un dossier distant, comme un dossier partagé. J'ai changé la base de données en un répertoire local et cela a fonctionné parfaitement.
J'ai un tel problème dans l'application, qui d'accès à SQLite à partir de 2 connexions - une en lecture seule et l'autre en écriture et en lecture. Il semble que cette connexion en lecture seule ait bloqué l'écriture à partir de la deuxième connexion. Enfin, il s'avère qu'il est nécessaire de finaliser ou, au moins, de réinitialiser les instructions préparées IMMÉDIATEMENT après leur utilisation. Jusqu'à ce que l'instruction préparée soit ouverte, la base de données était bloquée pour écriture.
N'OUBLIEZ PAS D'APPEL:
sqlite_reset(xxx);
ou
sqlite_finalize(xxx);
Certaines fonctions, comme INDEX'ing, peuvent prendre beaucoup de temps - et verrouillent toute la base de données en cours d'exécution. Dans de tels cas, il est possible que le fichier journal ne soit même pas utilisé!
Donc, le meilleur/seul moyen de vérifier si votre base de données est verrouillée car un processus y écrit activement (et vous devriez donc le laisser tranquille jusqu'à ce que son opération soit terminée) est de md5 (ou de md5sum sur certains systèmes) le fichier deux fois . Si vous obtenez une somme de contrôle différente, la base de données est en cours d'écriture et vous ne voulez vraiment PAS tuer ce processus car vous pouvez facilement vous retrouver avec une table/base de données corrompue.
Je le répète, car il est important - la solution n'est PAS de trouver le programme de verrouillage et de le tuer - mais de savoir si la base de données dispose d'un verrou en écriture pour une bonne raison, et ce, à partir de là. Parfois, la solution correcte est juste une pause-café.
La seule façon de créer cette situation verrouillée, mais non écrite, est si votre programme exécute BEGIN EXCLUSIVE
, car il voulait effectuer des modifications de table ou autre chose, puis, pour une raison quelconque, n'envoie jamais une END
par la suite, et le le processus ne se termine jamais. Il est très peu probable que les trois conditions soient remplies dans un code correctement écrit. Ainsi, 99 fois sur 100, lorsque quelqu'un veut tuer -9 son processus de verrouillage, le processus de verrouillage verrouille votre base de données pour une bonne raison. En général, les programmeurs n’ajoutent pas la condition BEGIN EXCLUSIVE
à moins qu’ils n’en aient vraiment besoin, car cela évite les accès simultanés et augmente le nombre de plaintes des utilisateurs. SQLite lui-même ne l'ajoute que lorsqu'il en a vraiment besoin (comme lors de l'indexation).
Enfin, le statut «verrouillé» n'existe pas À L'INTÉRIEUR du fichier, comme plusieurs réponses l'ont indiqué - il réside dans le noyau du système d'exploitation. Le processus qui a exécuté BEGIN EXCLUSIVE
a demandé au système d'exploitation de verrouiller le fichier. Même si votre processus exclusif s'est bloqué, votre système d'exploitation sera en mesure de déterminer s'il doit ou non conserver le verrouillage de fichier! Il n’est pas possible d’avoir une base de données verrouillée mais aucun processus ne la verrouille activement !! Quand il s’agit de savoir quel processus verrouille le fichier, il est généralement préférable d’utiliser lsof plutôt que l’unité de fusion bonne démonstration de pourquoi: https://unix.stackexchange.com/questions/94316/fuser-vs-lsof-to-check-files-in-use ). Sinon, si vous avez DTrace (OSX), vous pouvez utiliser iosnoop sur le fichier.
Ce lien résout le problème. : Quand SQLite donne: Erreur de la base de données verrouillée .__ Il a résolu mon problème peut vous être utile.
Et vous pouvez utiliser begin transaction et end transaction pour ne pas verrouiller la base de données à l'avenir.
Devrait être un problème interne d'une base de données ...
Pour moi, cela s’est manifesté après avoir essayé de parcourir la base de données avec "SQLite manager" ...
Donc, si vous ne trouvez pas un autre processus vous connecter à la base de données et que vous ne pouvez pas le réparer, essayez simplement cette solution radicale:
rake db:migrate
"Je viens de vivre quelque chose de similaire: mon application Web pouvait lire à partir de la base de données, mais ne pouvait effectuer aucune insertion ni mise à jour. Un redémarrage d'Apache a résolu le problème au moins temporairement.
Ce serait bien, cependant, de pouvoir retrouver la cause fondamentale.
lsof command sur mon environnement Linux m'a aidé à comprendre qu'un processus était suspendu en maintenant le fichier ouvert.
Tué le processus et le problème a été résolu.
Une des raisons courantes pour obtenir cette exception est lorsque vous essayez d'effectuer une opération d'écriture tout en conservant les ressources pour une opération de lecture. Par exemple, si vous sélectionnez une table, puis essayez de mettre à jour quelque chose que vous avez sélectionné sans fermer votre ResultSet au préalable.
J'ai eu cette erreur dans un scénario un peu différent de ceux décrits ici.
La base de données SQLite reposait sur un système de fichiers NFS partagé par 3 serveurs. Sur deux des serveurs, j'ai pu exécuter des requêtes sur la base de données, le troisième pensant recevoir le message "la base de données est verrouillée".
Le problème avec cette 3ème machine était qu’il n’y avait plus d’espace disponible sur /var
. Chaque fois que j'ai essayé d'exécuter une requête dans N'IMPORTE QUELLE base de données SQLite située dans ce système de fichiers, le message "la base de données est verrouillée" et cette erreur sur les journaux sont également affichés:
8 août 10:33:38 noyau server01: lockd: impossible de surveiller 172.22.84.87
Et celui-ci aussi:
8 août 10:33:38 server01 rpc.statd [7430]: Échec d'insertion: écriture de /var/lib/nfs/statd/sm/other.server.name.com: aucun espace disponible sur le périphérique 8 août 10:33:38 server01 rpc.statd [7430]: STAT_FAIL à server01 pour SM_MON du 172.22.84.87
Après la gestion de la situation spatiale, tout est redevenu normal.
Avant de désactiver l'option de redémarrage, il est utile de voir si vous pouvez trouver l'utilisateur de la base de données SQLite.
Sous Linux, on peut employer fuser
à cette fin:
$ fuser database.db
$ fuser database.db-journal
Dans mon cas, j'ai eu la réponse suivante:
philip 3556 4700 0 10:24 pts/3 00:00:01 /usr/bin/python manage.py Shell
Ce qui a montré que j'avais un autre programme Python avec le pid 3556 (manage.py) utilisant la base de données.
J'ai rencontré le même problème sous Mac OS X 10.5.7, qui exécutait des scripts Python à partir d'une session de terminal. Même si j’avais arrêté les scripts et que la fenêtre du terminal était située au niveau de l’invite de commande, cette erreur se produirait à la prochaine exécution. La solution consistait à fermer la fenêtre du terminal, puis à la rouvrir. Cela n'a pas de sens pour moi, mais cela a fonctionné.
J'ai eu le même problème. Apparemment, la fonction d'annulation semble écraser le fichier de base de données avec le journal, qui est identique au fichier de base de données, mais sans la modification la plus récente. J'ai implémenté ceci dans mon code ci-dessous et cela fonctionne bien depuis, alors qu'avant, mon code restait bloqué dans la boucle car la base de données restait verrouillée.
J'espère que cela t'aides
##############
#### 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 )
Une vieille question, avec beaucoup de réponses, voici les étapes que j'ai récemment suivies en lisant les réponses ci-dessus, mais dans mon cas, le problème était dû au partage de ressources cifs. Ce cas n’a pas été rapporté auparavant, alors espérons que cela aidera quelqu'un.
Essayez de forcer le mode de verrouillage sur l’ouverture de connexion avec
final SQLiteConfig config = new SQLiteConfig();
config.setReadOnly(false);
config.setLockingMode(LockingMode.NORMAL);
connection = DriverManager.getConnection(url, config.toProperties());
Si vous utilisez votre fichier de base de données SQLite sur un dossier partagé NFS, vérifiez this point de la FAQ SQLite et passez en revue vos options de configuration de montage pour vous assurer que vous évitez les verrous, comme décrit ici :
//myserver /mymount cifs username=*****,password=*****,iocharset=utf8,sec=ntlm,file,nolock,file_mode=0700,dir_mode=0700,uid=0500,gid=0500 0 0
Je viens d'avoir la même erreur ... Après 5 minutes de recherches sur Google, j'ai constaté que je n'avais pas fermé un Shell qui utilisait la base de données . Fermez-la et essayez à nouveau;)
Je recevais également des verrous sqlite dans une application C # .NET 4.6.1 que j'avais créée lors de la tentative d'écriture de données, mais pas lors de l'exécution de l'application dans Visual Studio sur ma machine de développement. Au lieu de cela, cela ne se produisait que lorsque l'application était installée et exécutée sur une machine Windows 10 distante.
Au départ, je pensais que c’était les autorisations du système de fichiers, mais il s’avère que les pilotes de package System.Data.SQLite (v1.0.109.2) que j’ai installés dans le projet à l’aide de Nuget étaient à l’origine du problème. J'ai supprimé le package NuGet et référencé manuellement une version plus ancienne des pilotes du projet. Une fois l'application réinstallée sur la machine distante, les problèmes de verrouillage ont disparu comme par magie. Je ne peux que penser qu’il ya eu un bogue avec les derniers pilotes ou le package Nuget.
Cette erreur s'est produite lors de l'utilisation de Delphi avec les composants LiteDAC . Il s'est avéré que cela ne s'est produit que lors de l'exécution de mon application à partir de Delphi IDE si la propriété Connected était définie sur True pour le composant de connexion SQLite (dans ce cas, TLiteConnection). .
Pour une raison quelconque, la base de données a été verrouillée. Voici comment je l'ai corrigé.
Cela fonctionne bien maintenant.
Dans mon cas, j'ai aussi eu cette erreur.
J'ai déjà vérifié s'il y avait d'autres processus pouvant être à l'origine d'une base de données verrouillée, tels que (SQLite Manager, d'autres programmes qui se connectent à ma base de données). Mais aucun autre programme ne s'y connecte, il s'agit simplement d'un autre SQLConnection actif dans la même application qui reste connecté.
Essayez de vérifier votre connexion SQLConnection active précédente qui était peut-être toujours connectée (déconnectez-la d'abord) avant d'établir une nouvelle connexion SQLConnection _ et nouvelle commande _.
En effet, une autre requête est en cours d'exécution sur cette base de données. SQLite est une base de données où la requête s'exécute de manière synchrone. Donc, si quelqu'un d'autre utilise cette base de données, vous obtiendrez cette erreur si vous effectuez une requête ou une transaction.
Arrêtez donc ce processus qui utilise la base de données particulière, puis exécutez votre requête.
Si vous essayez de déverrouiller la base de données Chrome en affichez-la avec SQLite , arrêtez simplement Chrome.
Les fenêtres
%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
vous pouvez essayer ceci: .timeout 100
pour définir le délai d'attente. Je ne sais pas ce qui se passe en ligne de commande mais en C # .Net quand je fais ceci: "UPDATE table-name SET column-name = value;"
Je reçois La base de données est verrouillée mais ce "UPDATE table-name SET column-name = value"
tout va bien.
Cela ressemble à lorsque vous ajoutez;, sqlite cherchera une commande supplémentaire.
D'après vos commentaires précédents, vous avez indiqué qu'un fichier journal était présent.
Cela peut signifier que vous avez ouvert une transaction (EXCLUSIVE?) Et que vous n'avez pas encore validé les données. Votre programme ou un autre processus a-t-il laissé le journal derrière?
Le redémarrage du processus sqlite examinera le fichier journal, nettoiera toutes les actions non validées et supprimera le fichier -journal.
Comme Seun Osewa l'a dit, parfois un processus zombie s'installera dans le terminal avec le verrou acquis, même si vous ne le croyez pas possible. Votre script s'exécute, se bloque et vous retournez à l'invite, mais il existe un processus zombie créé quelque part par un appel de bibliothèque et ce processus est verrouillé.
Fermer le terminal dans lequel vous étiez (sous OSX) pourrait fonctionner. Le redémarrage fonctionnera. Vous pouvez rechercher des processus "python" (par exemple) qui ne font rien et les tuer.
J'avais des erreurs de type "base de données est verrouillée" dans une application multi-thread, ce qui semble être le code de résultat SQLITE_BUSY , et je l'ai résolu avec le paramètre sqlite3_busy_timeout à une longueur convenable telle que 30000.
(Sur une note de côté, comme il est étrange que personne ne l'ait déjà découvert sur une question de 7 ans! SQLite est vraiment un projet particulier et étonnant ...)