Question

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?

Était-ce utile?

La solution

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 de base de données. 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 le processus ...

  

kill -9 5430

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

Autres conseils

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

Extrait de: http://random.kakaopor.hu/how-to-repair- an-sqlite-database

La page DatabaseIsLocked indiquée ci-dessous n'est plus disponible. La page Verrouillage de fichiers et accès simultanés 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

Le wiki SQLite DatabaseIsLocked fournit 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 sont les conditions qui pourraient 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 :

  

En cas de panne d'alimentation ou de panne d'alimentation et si un journal dynamique reste sur le disque, il est essentiel que le fichier de base de données d'origine et le journal dynamique 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 roulé en arrière. [...]

     

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 en vogue 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 autrement que par l'éducation 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 FAQ de sqlite recommande d’être prudente en ce qui concerne 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 auparavant. Est-ce reproductible?

Au fait, la présence d’un fichier journal est nécessairement synonyme d’un crash ou d’annulation de modifications. Sqlite a plusieurs modes de journal différents, et dans les modes PERSIST ou TRUNCATE, il laisse le fichier journal toujours en place et modifie le contenu pour indiquer s’il existe ou non des transactions partielles à annuler.

Si vous souhaitez supprimer une " base de données est verrouillée " erreur puis suivez ces étapes:

  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.

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.

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 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 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ée 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 copié dans son nom et son emplacement d'origine.

Utiliser un shell linux qui serait ...

mv mydata.db temp.db
cp temp.db mydata.db

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

J'ai trouvé très utile la documentation sur les différents états de verrouillage dans SQLite. Michael, si vous pouvez effectuer des lectures mais ne pouvez pas effectuer d'écriture 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 tel est le problème, vous devriez l'examiner à la place.

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

J'ai un tel problème au sein de l'application, qui consiste à accéder à SQLite à partir de deux connexions: l'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, peuvent prendre beaucoup de temps - et verrouiller toute la base de données en cours d’exécution. Dans de tels cas, le fichier journal n’est peut-être 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 (vous devez donc le laisser tranquille jusqu'à ce que son opération soit terminée) est d'utiliser 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 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 supprimer - mais de rechercher si la base de données dispose d'un verrou en écriture pour une bonne raison, puis de partir de là. Parfois, la solution correcte consiste simplement en 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 souhaitait apporter des modifications à une table ou autre chose, puis quoi que ce soit raison n’envoie jamais de FIN par la suite, et le processus ne se termine jamais . Les trois conditions remplies sont hautement improbables dans tout 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 , sauf indication contraire, 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 l'indiquent plusieurs réponses - 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 de se retrouver avec une base de données qui est verrouillée mais aucun processus ne la verrouille activement !! Pour déterminer quel processus verrouille le fichier, il est généralement préférable d’utiliser lsof plutôt que de fuser (c’est une bonne démonstration de la raison pour laquelle: 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.

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 localiser la cause première.

La commande

lsof sur mon environnement Linux m'a aidée à comprendre qu'un processus était en cours de blocage en maintenant le fichier ouvert.
Tué le processus et le problème a été résolu.

Ce lien résout le problème. : Lorsque 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 les opérations begin transaction et end transaction pour ne pas verrouiller la base de données à l'avenir.

Devrait être un problème interne à une base de données ...
Pour moi, il 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 vous ne pouvez simplement pas le réparer, juste essayer cette solution radicale:

  1. Fournissez pour exporter vos tables (vous pouvez utiliser le "Gestionnaire SQLite" sur Firefox)
  2. Si la migration modifie le schéma de votre base de données, supprimez la dernière migration ayant échoué
  3. Renommez votre "database.sqlite". fichier
  4. Exécutez " rake db: migrate " créer une nouvelle base de données de travail
  5. Fournissez 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 "

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 affichée à l’invite de commande, cette erreur se produirait lors de 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é.

Je viens d'avoir la même erreur. Après 5 minutes de recherche sur Google, j'ai constaté que je n'avais pas fermé un shell qui utilisait la base de données. Fermez-le et essayez à nouveau;)

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. Je l'ai implémenté 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 vous aidera

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 )

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 faites une sélection dans une table, puis essayez de mettre à jour quelque chose que vous avez sélectionné sans fermer d'abord votre ResultSet.

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 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) utilisant la base de données.

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 dispose des autorisations r / w sur le fichier.
  • Essayez de forcer le verrouillage des ouvertures 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 ce point de la FAQ SQLite, et passez en revue vos options de configuration de montage pour vous assurer que vos verrous sont évités, 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

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

Le problème avec cette 3ème machine était qu’il ne restait plus d’espace sur / var . Chaque fois que j'essayais d'exécuter une requête dans N'IMPORTE QUELLE base de données SQLite située dans ce système de fichiers, la "base de données est verrouillée". message et aussi 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 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 revenu à la normale.

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 examine le fichier journal, nettoie les actions non validées et supprime le fichier -journal.

Comme Seun Osewa l’a dit, parfois un processus zombie s’assoit 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 revenez à l'invite, mais il existe un processus zombie créé quelque part par un appel de bibliothèque et ce processus est verrouillé.

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

vous pouvez essayer ceci: .timeout 100 pour 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 ceci: "UPDATE nom-table SET nom-colonne = valeur;" > La base de données est verrouillée, mais < code> "nom de la table UPDATE SET nom de la colonne = valeur" , tout va bien.

On dirait que lorsque vous ajoutez;, sqlite va chercher une commande supplémentaire.

J'ai eu cette erreur lors de l'utilisation de Delphi avec les composants LiteDAC. En fait, cela ne s'est produit que lors de l'exécution de mon application à partir de l'EDI Delphi si la propriété Connected était définie sur True pour le composant de connexion SQLite (dans ce cas, TLiteConnection).

J'avais "la base de données est verrouillée". erreurs dans une application multithread également, ce qui semble être le code de résultat SQLITE_BUSY , et je a résolu le problème en définissant sqlite3_busy_timeout sur une longueur convenable telle que 30000.

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top