Domanda

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

Come posso sbloccare il database in modo che funzioni?

È stato utile?

Soluzione

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

  

uccidi -9 5430

... E il tuo database sarà sbloccato.

Altri suggerimenti

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- un-sqlite database

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

La pagina wiki di SQLite DatabaseIsLocked offre una buona spiegazione di questo messaggio di errore . Dichiara, 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.

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 rollback. [...]

     

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 fallirà se il processo non può bloccare il database. Come altri hanno già detto, una possibile ragione di ciò è che un altro processo lo ha attualmente 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 in merito all'accesso simultaneo ai database sui volumi NFS, a causa di implementazioni errate del blocco dei file NFS.

Non riesco a spiegare perché l'eliminazione 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.

Se desideri rimuovere un " database è bloccato " quindi segui questi passaggi:

  1. Copia il file del database in un'altra posizione.
  2. Sostituisci il database con il database copiato. In questo modo tutti i processi che stavano accedendo al tuo file di database sarebbero stati esclusi.

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.

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.

Ho avuto questo problema proprio ora, usando un database SQLite su un server remoto, memorizzato 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.

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.

Usare una shell Linux che sarebbe ...

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

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

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 altri processi ma le connessioni esistenti possono eseguire le letture, quindi se questo è il problema dovresti invece esaminarlo.

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.

Ho un simile 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 era bloccato per la scrittura.

NON DIMENTICARE LA CHIAMATA:

sqlite_reset(xxx);

o

sqlite_finalize(xxx);

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 passare 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 esegue BEGIN EXCLUSIVE , perché voleva fare alcune modifiche alla tabella o qualcosa del genere, quindi per qualunque cosa motivo non invia mai un END in seguito, 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 condizione BEGIN EXCLUSIVE a meno che non ne abbiano davvero bisogno, perché impedisce la concorrenza e aumenta i reclami degli utenti. SQLite stesso lo aggiunge solo quando è realmente necessario (ad esempio durante l'indicizzazione).

Infine, lo stato 'bloccato' non esiste DENTRO il file come indicato da diverse risposte - risiede nel kernel del sistema operativo. Il processo che ha eseguito BEGIN EXCLUSIVE ha 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é: https://unix.stackexchange.com/questions/94316/fuser-vs-lsof-to-check-files-in-use ) . In alternativa, se si dispone di DTrace (OSX), è possibile utilizzare iosnoop sul file.

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.

Il comando

lsof sul 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.

Questo collegamento risolve il problema. : Quando Sqlite indica: errore di blocco del database Ha risolto il mio problema che potrebbe esserti utile.

E puoi utilizzare la transazione di inizio e fine per non bloccare il database in futuro.

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

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

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 al prompt dei comandi, questo errore avrebbe restituito la volta successiva. La soluzione era chiudere la finestra del terminale e quindi riaprirla. Non ha senso per me, ma ha funzionato.

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

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 bene da allora, mentre prima il mio codice si sarebbe bloccato nel loop poiché il database rimaneva bloccato.

Spero che questo 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 )

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 selezioni da una tabella e poi provi ad AGGIORNARE qualcosa che hai selezionato senza prima chiudere il ResultSet.

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

Su Linux, si può impiegare fuser a tal fine:

$ fuser database.db

$ fuser database.db-journal

Nel mio caso ho ricevuto 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) che utilizzava il database.

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.

  • Verifica che nessuna connessione rimanga aperta nel tuo codice java.
  • Verifica che nessun altro processo stia utilizzando il tuo file db di SQLite con lsof.
  • Verifica che il proprietario dell'utente del tuo 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 si utilizza il file db di SQLite su una cartella condivisa NFS, selezionare questo punto di SQLite faq e rivedi le opzioni di configurazione del 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

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, il terzo ha pensato che stavo ottenendo il "database è bloccato" messaggio.

Il vantaggio di questa terza macchina era che non era rimasto spazio su / var . Ogni volta che ho provato a eseguire una query in QUALSIASI database SQLite situato in questo filesystem, ho ottenuto che il "database è bloccato" messaggio e anche questo errore sui registri:

  

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

E anche questo:

  

8 ago 10:33:38 server01 rpc.statd [7430]: impossibile inserire: writing /var/lib/nfs/statd/sm/other.server.name.com: spazio insufficiente sul dispositivo   8 ago 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à.

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 confermate e rimuoverà il file -journal.

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à. Puoi cercare " python " processi (ad esempio) che non fanno nulla e li uccidono.

puoi provare questo: .timeout 100 per impostare il timeout. Non so cosa succede nella riga di comando ma in C # .Net quando lo faccio: " UPDATE nome-tabella SET nome-colonna = valore; " ottengo Database bloccato ma questo < codice> " UPDATE nome-tabella SET nome-colonna = valore " va bene.

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

Ho riscontrato questo errore durante l'utilizzo di Delphi con i componenti LiteDAC. Alla fine è successo solo mentre eseguivo la mia app dall'IDE Delphi se la proprietà Connected era impostata su True per il componente di connessione SQLite (in questo caso TLiteConnection).

Avevo " il database è bloccato " errori anche in un'applicazione multi-thread, che sembra essere il SQLITE_BUSY e I risolto impostando 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 strano e straordinario ...)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top