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

269
sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked

Comment déverrouiller la base de données pour que cela fonctionne?

ryantm
la source
Un autre processus peut accéder au fichier de base de données - avez-vous vérifié lsof?
exister le
J'ai eu le même problème, le problème était dans l'antivirus lorsque je le désactive, mon application fonctionne bien, mais quand je l'active, je trouve l'erreur "la base de données est verrouillée", j'espère que cela vous aidera.
user8510915

Réponses:

267

Dans Windows, vous pouvez essayer ce programme http://www.nirsoft.net/utils/opened_files_view.html pour découvrir que le processus gère le fichier db. Essayez de fermer 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 simplement le processus ...

tuer -9 5430

... Et votre base de données sera déverrouillée.

noneno
la source
19
... avec la mise en garde évidente que vous devez savoir ce que vous faites. Si c'est un processus sans importance, cela killdevrait aller, mais vous devez faire attention à le tuer correctement, et il kill -9est probablement faux et / ou excessif. Si le processus est suspendu et ne mourra pas autrement, vous en avez parfois besoin kill -9. Mais vous ne voulez pas aller tuer le travail de production principal juste pour pouvoir signaler que la base de données n'est plus verrouillée!
tripleee
La solution la plus simple serait de simplement redémarrer votre ordinateur.
chacham15
7
@ chacham15: vous supposez que la base de données se trouve sur "mon" ordinateur et vous ignorez la possibilité que de nombreux processus importants s'exécutent sur le même ordinateur que celui avec la base de données verrouillée. La solution «plus simple» n'est jamais aussi simple que cela;)
tzot
1
@KyleCarlson - sqlite et mysql sont fondamentalement différents à cet égard. Il n'y a rien de particulièrement mal avec le navigateur SQLite-db.
Berry Tsakala
6
Cette solution suppose qu'un processus verrouille le fichier. Il est possible qu'un processus se bloque en laissant le fichier SQLite dans un état inutilisable. Dans ce cas, voir ma réponse.
robert
90

J'ai provoqué le verrouillage de ma base de données sqlite en plantant une application lors d'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

robert
la source
4
sqlite3:sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
woky
Ne travaille pas pourFOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
gies0r
52

La page DatabaseIsLocked répertoriée ci-dessous n'est plus disponible. La page Verrouillage de fichiers et accès simultané décrit les modifications liées au verrouillage de fichiers introduites dans la v3 et peut être utile aux futurs lecteurs. https://www.sqlite.org/lockingv3.html

La page SQLite wiki 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 que quelque chose dans votre processus détient un verrou et quelles conditions pourraient conduire à un faux positif.

convertisseur42
la source
2
Le problème est que la page est incorrecte ou obsolète: j'ai un processus qui ne fait littéralement rien d'autre qu'un seul INSERT qui reçoit ce message verrouillé: il n'est pas possible que ce processus ait provoqué le verrouillage. Le problème était dans un autre processus parlant à la même base de données.
Dan Jameson,
4
@ converter42 Lien rompu.
Ole Tange
32

La suppression du fichier -journal semble être une idée terrible. Il est là pour permettre à sqlite de restaurer la base de données dans un état cohérent après un crash. Si vous le supprimez alors que la base de données est dans un état incohérent, vous vous retrouvez avec une base de données corrompue. Citant une page du site sqlite :

Si une panne ou une coupure de courant se produit et qu'un journal actif est laissé 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 ceci: Une panne de courant se produit. Une fois le courant rétabli, un utilisateur ou un administrateur système bien intentionné 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 l'accident, il y a aussi un journal chaud nommé "important.data-journal". L'utilisateur supprime ensuite le journal actif, 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 censé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, l'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 consiste à remplacer le fichier de base de données par une nouvelle copie qui n'est pas verrouillée sur le serveur NFS (mv database.db original.db; cp original.db database.db). Notez que la FAQ sqlite recommande la prudence concernant l'accès simultané aux bases de données sur les volumes NFS, en raison des implémentations bogues du verrouillage des fichiers 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?

Soit dit en passant, la présence d'un fichier -journal ne signifie pas nécessairement qu'il y a eu un plantage ou qu'il y a des modifications à annuler. Sqlite a plusieurs modes de journal différents et dans les modes PERSIST ou TRUNCATE, il laisse toujours le fichier -journal en place et modifie le contenu pour indiquer s'il y a ou non des transactions partielles à annuler.

Aaron
la source
23

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 qui accédaient à votre fichier de base de données.
vinayak jadi
la source
2
J'ai essayé 'fuser <DB>' comme décrit ci-dessus, mais cela n'a pas fonctionné. Ces étapes simples fonctionnent pour moi.
Jackie Yeh
Dans mon cas, j'ai également dû redémarrer mon ordinateur portable Jupyter.
Victor
15

Si un processus a un verrou sur 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.


la source
48
alors comment débloquer la base de données?
Erik Kaplun
4
Ce n'est tout simplement pas vrai. Les verrous sont maintenus par l'OS. Lisez la réponse ci-dessous.
JJ
13

les fichiers db SQLite ne sont que des fichiers, donc la première étape serait de 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 DB SQLite GUI avec la base de données ouverte. Vous pouvez 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 voyez cela si un thread différent ou une application telle que SQLite Database Browser a la base de données ouverte pour l'écriture.

Heat Miser
la source
4
D'après mon expérience, SQLite Database Browser (SDB) verrouille de manière reproductible une base de données si vous modifiez des données avec mais ne l'enregistrez pas dans SDB. Si vous l'enregistrez, il libère le verrou.
Chelonian du
Je peux insérer mais je ne peux pas supprimer.
Wennie
10

J'ai eu ce problème tout à l'heure, en utilisant une base de données SQLite sur un serveur distant, stockée sur une monture NFS. SQLite n'a pas pu obtenir de verrou après que la session shell distante que j'ai utilisée s'est arrêtée alors que la base de données était ouverte.

Les recettes de récupération suggérées ci-dessus n'ont pas fonctionné pour moi (y compris l'idée de d'abord déplacer puis de recopier la base de données). Mais après l'avoir copiée sur un système non NFS, la base de données est devenue utilisable et aucune donnée ne semble avoir été perdue.

jogojapan
la source
9

Mon verrou a été provoqué par le plantage du système et non par un processus de blocage. Pour résoudre ce problème, j'ai simplement renommé le fichier, puis je l'ai recopié vers son nom et son emplacement d'origine.

Utiliser un shell Linux qui serait ...

mv mydata.db temp.db
cp temp.db mydata.db
Ben L
la source
solution très simple, résoudre mon problème d'une base de données verrouillée sur un lecteur réseau.
Maverick2805
7

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

user1900210
la source
4

J'ai trouvé la documentation des différents états de verrouillage dans SQLite très utile. Michael, si vous pouvez effectuer des lectures mais ne pouvez pas effectuer d'é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 n'a pas encore exécuté l'écriture. Si vous utilisez SQLite3, il y a un nouveau verrou appelé PENDING où plus aucun processus n'est autorisé à se connecter mais les connexions existantes peuvent toujours effectuer des lectures, donc si c'est le problème, vous devriez le regarder à la place.

Kyle Cronin
la source
4

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

Zequez
la source
3

J'ai un tel problème dans l'application, qui accède à SQLite à partir de 2 connexions - l'une était en lecture seule et la seconde pour l'écriture et la 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 déclarations préparées IMMÉDIATEMENT après utilisation. Jusqu'à l'ouverture de l'instruction préparée, la base de données a été bloquée pour l'écriture.

N'OUBLIEZ PAS D'APPEL:

sqlite_reset(xxx);

ou

sqlite_finalize(xxx);
Mike Keskinov
la source
3

Certaines fonctions, comme INDEX'ing, peuvent prendre très longtemps - et elles verrouillent toute la base de données pendant son exécution. Dans des cas comme celui-ci, il est possible qu'il n'utilise même pas le fichier journal!

Donc, le meilleur / seul moyen de vérifier si votre base de données est verrouillée car un processus y écrit activement (et donc vous devriez le laisser tranquille jusqu'à ce qu'il soit terminé) est de md5 (ou 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 VRAIMENT pas tuer -9 ce processus car vous pouvez facilement vous retrouver avec une table / base de données corrompue si vous le faites.

Je le répète, car c'est important - la solution n'est PAS de trouver le programme de verrouillage et de le tuer - c'est de trouver si la base de données a un verrou en écriture pour une bonne raison, et de partir de là. Parfois, la bonne solution n'est qu'une pause-café.

La seule façon de créer cette situation verrouillée mais non en cours d'écriture est si votre programme s'exécute BEGIN EXCLUSIVE, car il voulait faire des modifications de table ou quelque chose, alors pour une raison quelconque, n'envoie jamais de ENDsuite et le processus ne se termine jamais . Les trois conditions remplies sont très improbables dans tout code correctement écrit, et en tant que tel 99 fois sur 100 lorsque quelqu'un veut tuer -9 son processus de verrouillage, le processus de verrouillage verrouille réellement votre base de données pour une bonne raison. Les programmeurs n'ajoutent généralement pas la BEGIN EXCLUSIVEcondition à moins qu'ils n'en aient vraiment besoin, car cela empêche la concurrence et augmente les 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 l'ont indiqué plusieurs réponses - il réside dans le noyau du système d'exploitation. Le processus exécuté BEGIN EXCLUSIVEa demandé au système d'exploitation qu'un verrou soit placé sur le fichier. Même si votre processus exclusif est tombé en panne, votre système d'exploitation sera en mesure de déterminer s'il doit maintenir le verrouillage du fichier ou non !! Il n'est pas possible de se retrouver avec une base de données qui est verrouillée mais aucun processus ne la verrouille activement !! Quand il s'agit de voir quel processus verrouille le fichier, il est généralement préférable d'utiliser lsof plutôt que de fusion (c'est une bonne démonstration de pourquoi: /unix/94316/fuser-vs-lsof- vérifier les fichiers en cours d'utilisation ). Alternativement, si vous avez DTrace (OSX), vous pouvez utiliser iosnoop sur le fichier.

JJ
la source
2

Quelque chose de similaire m'est arrivé - mon application Web a pu lire à partir de la base de données, mais n'a pu effectuer aucune insertion ou 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 profonde.

Michael Cox
la source
2

La commande lsof sur mon environnement Linux m'a aidé à comprendre qu'un processus se bloquait en gardant le fichier ouvert.
Tué le processus et le problème a été résolu.

PinkSheep
la source
2


Cela devrait être le 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, connectez-vous à la base de données et que vous ne pouvez pas le corriger, essayez simplement cette solution radicale:

  1. Prévoyez d'exporter vos tables (vous pouvez utiliser "SQLite manager" sur Firefox)
  2. Si la migration modifie votre schéma de base de données, supprimez la dernière migration qui a é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 bonnes autorisations à la base de données pour l'importation de table
  6. Importez vos tables sauvegardées
  7. Écrivez la nouvelle migration
  8. Exécutez-le avec " rake db:migrate"
Davide Ganz
la source
1

J'ai rencontré ce même problème sur Mac OS X 10.5.7 en exécutant 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 se trouvait à l'invite de commande, cela donnerait cette erreur lors de sa prochaine exécution. La solution était de fermer la fenêtre du terminal puis de l'ouvrir à nouveau. Ça n'a pas de sens pour moi, mais ça a marché.

Shawn Swaner
la source
1

J'ai juste eu la même erreur. Après 5 minets sur Google, j'ai découvert que je n'avais pas fermé un obus qui utilisait la base de données. Fermez-le et réessayez;)

Couler
la source
1

J'ai eu le même problème. Apparemment, la fonction de restauration semble remplacer le fichier db par le journal qui est le même que le fichier db mais sans la modification la plus récente. J'ai implémenté cela dans mon code ci-dessous et cela fonctionne bien depuis lors, alors qu'avant mon code resterait 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 )
Geai
la source
1

Une raison courante pour obtenir cette exception est lorsque vous essayez d'effectuer une opération d'écriture tout en conservant des ressources pour une opération de lecture. Par exemple, si vous sélectionnez dans une table, puis essayez de METTRE À JOUR quelque chose que vous avez sélectionné sans fermer d'abord votre ResultSet.

Martin Carney
la source
1

Je rencontrais également des erreurs "la base de données est verrouillée" dans une application multi-thread, qui semble être le code de résultat SQLITE_BUSY , et je l'ai résolu en définissant sqlite3_busy_timeout sur quelque chose de convenablement long comme 30000.

(En passant, comme c'est étrange que sur une question de 7 ans personne ne l'ait déjà découvert! SQLite est vraiment un projet particulier et étonnant ...)

Stijn Sanders
la source
1

Avant de descendre l'option de redémarrage, il vaut la peine de voir si vous pouvez trouver l'utilisateur de la base de données sqlite.

Sous Linux, on peut employer fuserà cet effet:

$ fuser database.db

$ fuser database.db-journal

Dans mon cas, j'ai obtenu 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) en utilisant la base de données.

Philip Clarke
la source
1

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 des ressources cifs. Ce cas n'a pas été signalé précédemment, alors espérons qu'il aide 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 db SQLite avec lsof.
  • Vérifiez que le propriétaire de l'utilisateur de votre processus jvm en cours d'exécution dispose d'autorisations de lecture / écriture 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 db SQLite sur un dossier partagé NFS, vérifiez ce point de la FAQ SQLite et passez en revue vos options de configuration de montage pour vous assurer d'éviter 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
kothvandir
la source
1

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 2 des serveurs, j'ai pu exécuter des requêtes sur la base de données avec succès, sur le troisième, je pensais recevoir le message "la base de données est verrouillée".

Le truc avec cette 3ème machine, c'est qu'il ne restait plus d'espace /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, j'ai reçu le message "la base de données est verrouillée" et également cette erreur sur les journaux:

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 de l'insertion: écriture /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 de 172.22.84.87

Après la gestion de la situation spatiale, tout est revenu à la normale.

ederribeiro
la source
1

Si vous essayez de déverrouiller la base de données Chrome pour la visualiser avec SQLite , 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
Bob Stein
la source
0

D'après vos commentaires précédents, vous avez dit qu'un dossier de 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 vous ??

Le redémarrage du processus sqlite examinera le fichier journal et nettoiera toutes les actions non validées et supprimera le fichier -journal.


la source
0

Comme l'a dit Seun Osewa, parfois un processus zombie se trouve dans le terminal avec une serrure acquise, même si vous ne le pensez pas possible. Votre script s'exécute, se bloque et vous revenez à l'invite, mais il y a un processus zombie engendré quelque part par un appel à la bibliothèque, et ce processus a le verrou.

La fermeture du terminal dans lequel vous étiez (sous OSX) peut fonctionner. Le redémarrage fonctionnera. Vous pouvez rechercher des processus "python" (par exemple) qui ne font rien et les tuer.

wisty
la source
0

vous pouvez essayer ceci: .timeout 100pour définir le délai d'expiration. Je ne sais pas ce qui se passe en ligne de commande mais en C # .Net quand je fais cela: "UPDATE table-name SET column-name = value;"je reçois la base de données est verrouillée mais cela"UPDATE table-name SET column-name = value" ça va bien.

Il ressemble à ce que vous ajoutez; sqlite recherchera une commande supplémentaire.

Dzung Nguyen
la source