web-dev-qa-db-fra.com

Comment débloquer une base de données SQLite?

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?

224
ryantm

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.

230
noneno

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

85
robert

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. 

51
converter42

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.

27
Aaron

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.

12
Phil

Si vous souhaitez supprimer une erreur "la base de données est verrouillée", procédez comme suit:

  1. Copiez votre fichier de base de données vers un autre emplacement. 
  2. Remplacez la base de données par la base de données copiée. Cela déréférencera tous les processus ayant accédé à votre fichier de base de données.
12
vinayak jadi

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.

10
Heat Miser

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.

9
jogojapan

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
4
Ben L

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.

4
Kyle Cronin

J'ai ajouté "Pooling=true" à la chaîne de connexion et cela a fonctionné.

4
user1900210

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.

4
Zequez

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);
3
Mike Keskinov

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.

3
J.J

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.

2
shreeji

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:

  1. Fournissez pour exporter vos tables (vous pouvez utiliser "Gestionnaire SQLite" sur Firefox)
  2. Si la migration modifie votre schéma de base de données, supprimez la dernière migration ayant échoué.
  3. Renommez votre fichier "database.sqlite"
  4. Exécutez "rake db: migrate" pour créer une nouvelle base de données de travail
  5. Fournir pour donner les autorisations appropriées à la base de données pour l'importation de la table
  6. Importez vos tables sauvegardées
  7. Écrire la nouvelle migration
  8. Exécutez-le avec "rake db:migrate"
2
Davide Ganz

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.

2
Michael Cox

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.

2
PinkSheep

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.

1
Martin Carney

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.

1
ederribeiro

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.

1
Philip Clarke

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é.

1
Shawn Swaner

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

mon code python

##############
#### 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 )
1
Jared

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.

  • Vérifiez qu'aucune connexion n'est laissée ouverte dans votre code Java. 
  • Vérifiez qu'aucun autre processus n'utilise votre fichier de base de données SQLite avec lsof. 
  • Vérifiez que le propriétaire de votre processus jvm en cours d'exécution dispose d'autorisations r/w sur le fichier.
  • 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
1
kothvandir

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;)

1
Flow

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.

0
Mr Rowe

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). . 

0
TheSteven

Pour une raison quelconque, la base de données a été verrouillée. Voici comment je l'ai corrigé.

  1. J'ai téléchargé le fichier sqlite sur mon système (FTP)
  2. Supprimé le fichier sqlite en ligne
  3. Re-téléchargé le fichier chez l'hébergeur

Cela fonctionne bien maintenant.

0
Mohsin

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 _.

0
Wennie

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.

0
Alok Kumar Singh

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
0
Bob Stein

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.

0
nXqd

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.

0
daivd cameron

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.

0
wisty

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 ...)

0
Stijn Sanders