Come sblocco un database SQLite?


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

Come posso sbloccare il database in modo che funzioni?


Potrebbe esserci un altro processo di accesso al file del database - hai controllato lsof?
inesistente il

Ho avuto lo stesso problema, il problema era nell'antivirus quando lo disattivo la mia app funziona bene, ma quando lo attivo trovo l'errore "il database è bloccato", spero che ti possa aiutare.
user8510915

Risposte:


267

In Windows puoi provare questo programma http://www.nirsoft.net/utils/opened_files_view.html per scoprire che il processo sta gestendo il file db. Prova a chiudere quel programma per sbloccare il database

In Linux e macOS puoi fare qualcosa di simile, ad esempio, se il tuo file bloccato è development.db:

$ fuser development.db

Questo comando mostrerà quale processo sta bloccando il file:

> development.db: 5430

Basta uccidere il processo ...

uccidere -9 5430

... E il tuo database sarà sbloccato.


19
... con l'evidente avvertimento che devi sapere cosa stai facendo. Se è un processo non importante, allora killdovrebbe andare bene, ma devi stare attento a ucciderlo correttamente, ed kill -9è probabilmente sbagliato e / o eccessivo. Se il processo viene sospeso e non morirà altrimenti, a volte è necessario kill -9. Ma non vuoi andare a uccidere il lavoro di produzione principale solo per poter segnalare che il database non è più bloccato!
Tripleee,

La soluzione più semplice sarebbe quella di riavviare il computer.
chacham15,

7
@ chacham15: supponi che il database si trovi sul "mio" computer e ignori la possibilità di eseguire molti processi importanti sullo stesso computer di quello con il database bloccato. La soluzione "più semplice" non è mai così semplice;)
tzot

1
@KyleCarlson - sqlite e mysql sono fondamentalmente diversi in questo aspetto. Non c'è nulla di particolarmente sbagliato con SQLite-db-browser.
Berry Tsakala,

6
Questa soluzione presuppone che sia presente un processo che blocca il file. È possibile che un processo si sia arrestato in modo anomalo lasciando il file SQLite in uno stato inutilizzabile. In tal caso, vedi la mia risposta.
Robert

90

Ho causato il blocco del mio db sqlite bloccando un'app durante una scrittura. Ecco come l'ho risolto:

echo ".dump" | sqlite old.db | sqlite new.db

Tratto da: http://random.kakaopor.hu/how-to-repair-an-sqlite-database


4
sqlite3:sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
woky,

Non funziona perFOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
gies0r

52

La pagina DatabaseIsLocked elencata di seguito non è più disponibile. La pagina Blocco e concorrenza dei file descrive le modifiche relative al blocco dei file introdotte nella v3 e può essere utile per i lettori futuri.https://www.sqlite.org/lockingv3.html

Il SQLite wiki DatabaseIsLocked pagina offre una buona spiegazione di questo messaggio di errore. Indica, in parte, che la fonte della contesa è interna (al processo che emette l'errore).

Ciò che questa pagina non spiega è come SQLite decide che qualcosa nel tuo processo ha un blocco e quali condizioni potrebbero portare a un falso positivo.


2
Il problema è che la pagina non è corretta o non è aggiornata: ho un processo che non fa letteralmente altro che un singolo INSERT che riceve quel messaggio bloccato: non è possibile che questo processo abbia causato il blocco. Il problema era in un altro processo che parlava con lo stesso DB.
Dan Jameson,

4
@ converter42 Collegamento interrotto.
Ole Tange,

32

L'eliminazione del file -journal sembra un'idea terribile. È lì per consentire a sqlite di ripristinare il database in uno stato coerente dopo un arresto anomalo. Se lo elimini mentre il database si trova in uno stato incoerente, rimarrai con un database danneggiato. Citando una pagina dal sito sqlite :

Se si verifica un arresto anomalo o un'interruzione dell'alimentazione e un disco caldo viene lasciato sul disco, è essenziale che il file del database originale e il giornale caldo rimangano sul disco con i loro nomi originali fino a quando il file del database non viene aperto da un altro processo SQLite e ripristinato . [...]

Sospettiamo che si verifichi una modalità di errore comune per il recupero di SQLite in questo modo: si verifica un'interruzione di corrente. Dopo il ripristino dell'alimentazione, un utente o un amministratore di sistema ben intenzionato inizia a cercare danni sul disco. Vedono il loro file di database chiamato "important.data". Questo file è forse familiare a loro. Ma dopo l'incidente, c'è anche un diario caldo chiamato "important.data-journal". L'utente quindi elimina il journal caldo, pensando che sta aiutando a ripulire il sistema. Non conosciamo alcun modo per impedirlo se non la formazione degli utenti.

Il rollback dovrebbe avvenire automaticamente alla successiva apertura del database, ma non riuscirà se il processo non è in grado di bloccare il database. Come altri hanno già detto, una possibile ragione di ciò è che un altro processo attualmente lo ha aperto. Un'altra possibilità è un blocco NFS non aggiornato, se il database si trova su un volume NFS. In tal caso, una soluzione alternativa consiste nel sostituire il file di database con una nuova copia non bloccata sul server NFS (mv database.db original.db; cp original.db database.db). Si noti che le FAQ di sqlite raccomandano cautela riguardo all'accesso simultaneo ai database sui volumi NFS, a causa delle implementazioni errate del blocco dei file NFS.

Non riesco a spiegare perché la cancellazione di un file -journal ti permetterebbe di bloccare un database che prima non potevi. È riproducibile?

A proposito, la presenza di un file -journal non significa necessariamente che si sia verificato un arresto anomalo o che ci siano modifiche da ripristinare. Sqlite ha alcune diverse modalità journal e nelle modalità PERSIST o TRUNCATE lascia sempre il file -journal in atto e cambia il contenuto per indicare se ci sono o meno transazioni parziali da ripristinare.


23

Se si desidera rimuovere un errore "il database è bloccato", attenersi alla seguente procedura:

  1. Copia il tuo file di database in un'altra posizione.
  2. Sostituire il database con il database copiato. Ciò determinerà tutti i processi che stavano accedendo al file del database.

2
Ho provato 'fuser <DB>' come descritto sopra, ma non ha funzionato. Questi semplici passaggi funzionano per me.
Jackie Yeh,

Nel mio caso ho anche dovuto riavviare il mio notebook Jupyter.
Victor,

15

Se un processo ha un blocco su un DB SQLite e si arresta in modo anomalo, il DB rimane bloccato in modo permanente. Questo è il problema. Non è che qualche altro processo abbia un lucchetto.


48
quindi come sbloccare il db?
Erik Kaplun,

4
Questo non è vero. I blocchi sono gestiti dal sistema operativo. Leggi la risposta qui sotto.
JJ,

13

i file db di SQLite sono solo file, quindi il primo passo sarebbe assicurarsi che non sia di sola lettura. L'altra cosa da fare è assicurarsi di non avere una sorta di visualizzatore di SQLite DB GUI con il DB aperto. È possibile che il DB sia aperto in un'altra shell oppure il codice potrebbe avere il DB aperto. In genere si vedrebbe questo se un thread diverso o un'applicazione come SQLite Database Browser ha il DB aperto per la scrittura.


4
Nella mia esperienza, SQLite Database Browser (SDB) blocca in modo riproducibile un database se si modificano i dati con esso ma non li si salva in SDB. Se lo salvi, rilascia il blocco.
Chelonian

Posso inserire ma non posso cancellare.
Wennie,

10

Ho avuto questo problema proprio ora, usando un database SQLite su un server remoto, archiviato su un mount NFS. SQLite non è stato in grado di ottenere un blocco dopo l'arresto anomalo della sessione di shell remota che ho usato mentre il database era aperto.

Le ricette per il recupero suggerite sopra non hanno funzionato per me (inclusa l'idea di spostare prima e quindi copiare nuovamente il database). Ma dopo averlo copiato su un sistema non NFS, il database è diventato utilizzabile e non sembra che i dati siano andati persi.


9

Il mio blocco è stato causato dal crash del sistema e non da un processo sospeso. Per risolvere questo, ho semplicemente rinominato il file e poi l'ho copiato nel nome e nella posizione originali.

Utilizzando una shell Linux che sarebbe ...

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

soluzione molto semplice, risolvendo il mio problema di un database bloccato su un'unità di rete.
Maverick2805,

7

Ho aggiunto " Pooling=true" alla stringa di connessione e ha funzionato.


4

Ho trovato molto utile la documentazione dei vari stati di blocco in SQLite. Michael, se è possibile eseguire letture ma non è possibile eseguire scritture nel database, ciò significa che un processo ha ottenuto un blocco RISERVATO sul database ma non ha ancora eseguito la scrittura. Se stai usando SQLite3, c'è un nuovo blocco chiamato PENDING in cui non è più possibile connettere più processi ma le connessioni esistenti possono eseguire le letture, quindi se questo è il problema dovresti invece esaminarlo.


4

Questo errore può essere generato se il file si trova in una cartella remota, come una cartella condivisa. Ho cambiato il database in una directory locale e ha funzionato perfettamente.


3

Ho un tale problema all'interno dell'app, che accede a SQLite da 2 connessioni: una era di sola lettura e la seconda per la scrittura e la lettura. Sembra che quella connessione di sola lettura abbia bloccato la scrittura dalla seconda connessione. Infine, si scopre che è necessario finalizzare o, almeno, ripristinare le istruzioni preparate IMMEDIATAMENTE dopo l'uso. Fino all'apertura dell'istruzione preparata, il database è stato bloccato per la scrittura.

NON DIMENTICARE LA CHIAMATA:

sqlite_reset(xxx);

o

sqlite_finalize(xxx);

3

Alcune funzioni, come INDEX, possono richiedere molto tempo e blocca l'intero database mentre è in esecuzione. In casi del genere, potrebbe anche non utilizzare il file journal!

Quindi il modo migliore / unico per verificare se il tuo database è bloccato perché un processo sta ATTIVAMENTE scrivendo su di esso (e quindi dovresti lasciarlo da solo fino a quando non ha completato il suo funzionamento) è md5 (o md5sum su alcuni sistemi) il file due volte . Se si ottiene un checksum diverso, il database è in fase di scrittura e in realtà non si vuole davvero uccidere -9 quel processo perché si può facilmente finire con una tabella / database corrotto se lo si fa.

Lo ripeterò, perché è importante - la soluzione NON è trovare il programma di blocco e ucciderlo - è scoprire se il database ha un blocco di scrittura per una buona ragione, e andare da lì. A volte la soluzione corretta è solo una pausa caffè.

L'unico modo per creare questa situazione bloccata ma non scritta è se il tuo programma viene eseguito BEGIN EXCLUSIVE, perché voleva fare alcune modifiche alla tabella o qualcosa del genere, quindi per qualsiasi motivo non invia mai un ENDdopo, e il processo non termina mai . Tutte e tre le condizioni soddisfatte sono altamente improbabili in qualsiasi codice scritto correttamente, e come tale 99 volte su 100 quando qualcuno vuole uccidere -9 il loro processo di blocco, il processo di blocco sta effettivamente bloccando il database per una buona ragione. I programmatori in genere non aggiungono la BEGIN EXCLUSIVEcondizione a meno che non ne abbiano davvero bisogno, perché impedisce la concorrenza e aumenta i reclami degli utenti. Lo stesso SQLite lo aggiunge solo quando è realmente necessario (come durante l'indicizzazione).

Infine, lo stato "bloccato" non esiste all'interno del file, come indicato da diverse risposte, risiede nel kernel del sistema operativo. Il processo eseguito BEGIN EXCLUSIVEha richiesto al sistema operativo di inserire un blocco nel file. Anche se il tuo processo esclusivo è andato in crash, il tuo sistema operativo sarà in grado di capire se deve mantenere il blocco dei file o no !! Non è possibile finire con un database bloccato ma nessun processo lo sta bloccando attivamente !! Quando si tratta di vedere quale processo sta bloccando il file, in genere è meglio usare lsof piuttosto che fuser (questa è una buona dimostrazione del perché: /unix/94316/fuser-vs-lsof- per controllare i file in uso ). In alternativa, se si dispone di DTrace (OSX), è possibile utilizzare iosnoop sul file.


2

Mi è appena successo qualcosa di simile: la mia applicazione Web è stata in grado di leggere dal database, ma non è stato in grado di eseguire inserimenti o aggiornamenti. Un riavvio di Apache ha risolto il problema almeno temporaneamente.

Sarebbe bello, tuttavia, essere in grado di rintracciare la causa principale.


2

Il comando lsof nel mio ambiente Linux mi ha aiutato a capire che un processo era sospeso mantenendo il file aperto.
Ha ucciso il processo e il problema è stato risolto.



2

Dovrebbe essere un problema interno di un database ...
Per me si è manifestato dopo aver cercato di sfogliare il database con "Gestione SQLite" ...
Quindi, se non riesci a trovare un altro processo connettiti al database e non puoi risolverlo, prova questa soluzione radicale:

  1. Fornire per esportare le tabelle (è possibile utilizzare "Gestione SQLite" su Firefox)
  2. Se la migrazione modifica lo schema del database, eliminare l'ultima migrazione non riuscita
  3. Rinomina il tuo file "database.sqlite"
  4. Eseguire "rake db: migrate" per creare un nuovo database funzionante
  5. Fornire le autorizzazioni giuste al database per l'importazione della tabella
  6. Importa le tue tabelle di backup
  7. Scrivi la nuova migrazione
  8. Eseguilo con " rake db:migrate"

1

Ho riscontrato questo stesso problema su Mac OS X 10.5.7 eseguendo script Python da una sessione terminale. Anche se avevo interrotto gli script e la finestra del terminale era seduta al prompt dei comandi, alla successiva esecuzione avrebbe restituito questo errore. La soluzione era chiudere la finestra del terminale e quindi riaprirla. Non ha senso per me, ma ha funzionato.


1

Ho appena avuto lo stesso errore. Dopo 5 minatori su Google ho scoperto che non avevo chiuso una strega shell stava usando il db. Basta chiuderlo e riprovare;)


1

Ho avuto lo stesso problema. Apparentemente la funzione di rollback sembra sovrascrivere il file db con il journal che è lo stesso del file db ma senza la modifica più recente. Ho implementato questo nel mio codice qui sotto e ha funzionato benissimo da allora, mentre prima il mio codice si sarebbe bloccato nel loop mentre il database rimaneva bloccato.

Spero che questo ti aiuti

il mio codice 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

Un motivo comune per ottenere questa eccezione è quando si sta tentando di eseguire un'operazione di scrittura mentre si mantengono ancora le risorse per un'operazione di lettura. Ad esempio, se si SELEZIONA da una tabella e quindi si tenta di AGGIORNARE qualcosa che è stato selezionato senza chiudere prima il ResultSet.


1

Stavo riscontrando errori di "database bloccato" anche in un'applicazione multi-thread, che sembra essere il codice risultato SQLITE_BUSY e l'ho risolto con l'impostazione sqlite3_busy_timeout su qualcosa di adeguatamente lungo come 30000.

(A proposito, che strano che su una domanda di 7 anni nessuno lo abbia già scoperto! SQLite è davvero un progetto singolare e sorprendente ...)


1

Prima di disattivare l'opzione di riavvio, vale la pena vedere se è possibile trovare l'utente del database sqlite.

Su Linux, si può impiegare fusera tal fine:

$ fuser database.db

$ fuser database.db-journal

Nel mio caso ho ottenuto la seguente risposta:

philip    3556  4700  0 10:24 pts/3    00:00:01 /usr/bin/python manage.py shell

Il che ha dimostrato che avevo un altro programma Python con pid 3556 (manage.py) usando il database.


1

Una vecchia domanda, con molte risposte, ecco i passaggi che ho seguito recentemente leggendo le risposte sopra, ma nel mio caso il problema era dovuto alla condivisione delle risorse cifs. Questo caso non è stato segnalato in precedenza, quindi spero che aiuti qualcuno.

  • Controlla che nessuna connessione rimanga aperta nel tuo codice java.
  • Verifica che nessun altro processo stia utilizzando il tuo file db di SQLite con lsof.
  • Verificare che il proprietario dell'utente del processo jvm in esecuzione disponga delle autorizzazioni r / w sul file.
  • Prova a forzare la modalità di blocco sull'apertura della connessione con

    final SQLiteConfig config = new SQLiteConfig();
    
    config.setReadOnly(false);
    
    config.setLockingMode(LockingMode.NORMAL);
    
    connection = DriverManager.getConnection(url, config.toProperties());

Se stai usando il tuo file db di SQLite su una cartella condivisa NFS, controlla questo punto della domanda SQLite e rivedi le opzioni di configurazione di montaggio per assicurarti di evitare i blocchi, come descritto qui :

//myserver /mymount cifs username=*****,password=*****,iocharset=utf8,sec=ntlm,file,nolock,file_mode=0700,dir_mode=0700,uid=0500,gid=0500 0 0

1

Ho riscontrato questo errore in uno scenario un po 'diverso da quelli descritti qui.

Il database SQLite si basava su un filesystem NFS condiviso da 3 server. Su 2 dei server sono stato in grado di eseguire correttamente le query sul database, mentre il terzo pensava di ricevere il messaggio "il database è bloccato".

La cosa con questa terza macchina era che non aveva più spazio /var. Ogni volta che ho provato a eseguire una query in QUALSIASI database SQLite situato in questo filesystem ho ricevuto il messaggio "il database è bloccato" e anche questo errore sui registri:

8 agosto 10:33:38 kernel server01: lockd: impossibile monitorare 172.22.84.87

E anche questo:

8 agosto 10:33:38 server01 rpc.statd [7430]: impossibile inserire: writing /var/lib/nfs/statd/sm/other.server.name.com: spazio non disponibile sul dispositivo 8 agosto 10:33: 38 server01 rpc.statd [7430]: STAT_FAIL su server01 per SM_MON di 172.22.84.87

Dopo che la situazione spaziale è stata gestita, tutto è tornato alla normalità.


1

Se stai provando a sbloccare il database Chrome per visualizzarlo con SQLite , devi semplicemente chiudere Chrome.

finestre

%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

Dai tuoi commenti precedenti hai detto che era presente un file -journal.

Ciò potrebbe significare che hai aperto e (ESCLUSIVO?) Transazione e non hai ancora eseguito il commit dei dati. Il tuo programma o qualche altro processo ha lasciato indietro il -journal ??

Il riavvio del processo sqlite esaminerà il file journal e pulirà tutte le azioni non impegnate e rimuoverà il file -journal.


0

Come ha detto Seun Osewa, a volte un processo di zombi siederà nel terminale con una serratura acquisita, anche se non lo pensi possibile. Lo script viene eseguito, si arresta in modo anomalo e si ritorna al prompt, ma esiste un processo di zombi generato da qualche parte da una chiamata in libreria e quel processo ha il blocco.

La chiusura del terminale in cui ci si trovava (su OSX) potrebbe funzionare. Il riavvio funzionerà. Potresti cercare processi "python" (per esempio) che non stanno facendo nulla e ucciderli.


0

puoi provare questo: .timeout 100per impostare il timeout. Non so cosa succede nella riga di comando, ma in C # .Net quando faccio questo: "UPDATE table-name SET column-name = value;"Ottengo Database bloccato ma questo "UPDATE table-name SET column-name = value"va bene.

Sembra che quando si aggiunge; sqlite cercherà ulteriori comandi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.