Como desbloquear um banco de dados SQLite?

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

Como desbloquear o banco de dados para que isso funcione?

ryantm
fonte
Pode haver outro processo para acessar o arquivo do banco de dados - você verificou lsof?
inexistia 29/09/08
Eu tive o mesmo problema, o problema estava no antivírus quando eu o desativei, meu aplicativo funciona bem, mas quando eu o ativo, encontro algum erro "o banco de dados está bloqueado", espero que ajude você.
user8510915

Respostas:

267

No Windows, você pode tentar este programa http://www.nirsoft.net/utils/opened_files_view.html para descobrir que o processo está lidando com o arquivo db. Tente fechar esse programa para desbloquear o banco de dados

No Linux e no macOS, você pode fazer algo semelhante, por exemplo, se o arquivo bloqueado for development.db:

$ fuser development.db

Este comando mostrará qual processo está bloqueando o arquivo:

> development.db: 5430

Basta matar o processo ...

kill -9 5430

... E seu banco de dados será desbloqueado.

noneno
fonte
19
... com a ressalva óbvia de que você precisa saber o que está fazendo. Se for um processo sem importância kill, tudo bem, mas você deve ter cuidado para matá-lo adequadamente e kill -9provavelmente está errado e / ou exagero. Se o processo for interrompido e não morrerá, às vezes você precisa kill -9. Mas você não deseja interromper o trabalho principal de produção apenas para poder relatar que o banco de dados não está mais bloqueado!
Tripleee 21/10
A solução mais simples seria apenas reiniciar o computador.
chacham15
7
@ chacham15: você assume que o banco de dados está no computador "my" e ignora a possibilidade de muitos processos importantes em execução no mesmo computador que o banco de dados bloqueado. A solução “mais simples” nunca é tão simples;)
tzot
1
@KyleCarlson - sqlite e mysql são fundamentalmente diferentes nesse aspecto. Não há nada de particularmente errado com o SQLite-db-browser.
Berry Tsakala
6
Esta solução supõe que haja um processo bloqueando o arquivo. É possível que um processo tenha travado, deixando o arquivo SQLite em um estado inutilizável. Nesse caso, veja minha resposta.
21414 Robert
90

Fiz com que meu sqlite db ficasse bloqueado ao travar um aplicativo durante uma gravação. Aqui está como eu o consertei:

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

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

Robert
fonte
4
sqlite3:sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
woky 28/11
Não está trabalhando para #FOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
gies0r #
52

A página DatabaseIsLocked listada abaixo não está mais disponível. A página Bloqueio de arquivo e simultaneidade descreve as alterações relacionadas ao bloqueio de arquivo introduzidas na v3 e podem ser úteis para futuros leitores.https://www.sqlite.org/lockingv3.html

O wiki DatabaseiteLocked do SQLite página oferece uma boa explicação para essa mensagem de erro. Ele afirma, em parte, que a fonte da disputa é interna (ao processo que emite o erro).

O que esta página não explica é como o SQLite decide que algo em seu processo possui um bloqueio e que condições podem levar a um falso positivo.

converter42
fonte
2
O problema é que a página está incorreta ou desatualizada: eu tenho um processo que literalmente nada faz além de um único INSERT que está recebendo essa mensagem bloqueada: não é possível que esse processo tenha causado o bloqueio. O problema estava em outro processo conversando com o mesmo banco de dados.
Dan Jameson
4
@ converter42 Link quebrado.
precisa
32

Excluir o arquivo -journal parece uma péssima idéia. Está lá para permitir ao sqlite reverter o banco de dados para um estado consistente após uma falha. Se você o excluir enquanto o banco de dados estiver em um estado inconsistente, ficará com um banco de dados corrompido. Citando uma página do site sqlite :

Se ocorrer uma falha ou perda de energia e um hot journal for deixado no disco, é essencial que o arquivo de banco de dados original e o hot journal permaneçam no disco com seus nomes originais até que o arquivo de banco de dados seja aberto por outro processo SQLite e revertido . [...]

Suspeitamos que um modo de falha comum para recuperação do SQLite ocorra da seguinte maneira: Ocorre uma falha de energia. Após a restauração da energia, um usuário bem-intencionado ou administrador do sistema começa a procurar danos no disco. Eles veem o arquivo de banco de dados chamado "important.data". Esse arquivo talvez seja familiar para eles. Mas após o acidente, também existe um diário ativo chamado "important.data-journal". O usuário exclui o diário ativo, pensando que está ajudando a limpar o sistema. Não sabemos como evitar isso além da educação do usuário.

A reversão deve ocorrer automaticamente na próxima vez que o banco de dados for aberto, mas falhará se o processo não puder bloquear o banco de dados. Como outros já disseram, uma possível razão para isso é que outro processo está aberto no momento. Outra possibilidade é um bloqueio NFS antigo, se o banco de dados estiver em um volume NFS. Nesse caso, uma solução alternativa é substituir o arquivo do banco de dados por uma nova cópia que não esteja bloqueada no servidor NFS (mv database.db original.db; cp original.db database.db). Observe que as perguntas frequentes do sqlite recomendam cautela em relação ao acesso simultâneo a bancos de dados em volumes NFS, devido a implementações com erros do bloqueio de arquivos NFS.

Não sei explicar por que excluir um arquivo -journal permitiria bloquear um banco de dados que não era possível antes. Isso é reproduzível?

A propósito, a presença de um arquivo -journal não significa necessariamente que houve uma falha ou que há mudanças a serem revertidas. O Sqlite possui alguns modos de diário diferentes e, nos modos PERSIST ou TRUNCATE, deixa sempre o arquivo -journal no lugar e altera o conteúdo para indicar se há transações parciais para reverter ou não.

Aaron
fonte
23

Se você deseja remover um erro "o banco de dados está bloqueado", siga estas etapas:

  1. Copie seu arquivo de banco de dados para outro local.
  2. Substitua o banco de dados pelo banco de dados copiado. Isso desreferirá todos os processos que estavam acessando seu arquivo de banco de dados.
vinayak jadi
fonte
2
Tentei 'fusor <DB>' como descrito acima, mas não funcionou. Estes passos simples funcionam para mim.
Jackie Yeh
No meu caso, eu também tive que reiniciar o meu Jupyter Notebook.
Victor Victor
15

Se um processo tiver um bloqueio em um banco de dados SQLite e falhar, o banco de dados permanecerá bloqueado permanentemente. Esse é o problema. Não é que algum outro processo tenha um bloqueio.


fonte
48
Então, como desbloquear o db?
Erik Kaplun
4
Isso simplesmente não é verdade. Bloqueios são mantidos pelo sistema operacional. Leia a resposta abaixo.
JJ
13

os arquivos db SQLite são apenas arquivos, portanto, o primeiro passo seria garantir que não seja somente leitura. A outra coisa a fazer é garantir que você não tenha algum tipo de visualizador de SQLite DB da GUI com o DB aberto. Você pode ter o banco de dados aberto em outro shell ou seu código pode ter o banco de dados aberto. Normalmente, você veria isso se um thread ou aplicativo diferente, como o SQLite Database Browser, tivesse o banco de dados aberto para gravação.

Aversão ao calor
fonte
4
Na minha experiência, o SQLite Database Browser (SDB) bloqueia reprodutivelmente um banco de dados se você editar dados com ele, mas não salvá-lo no SDB. Se você salvá-lo, ele libera o bloqueio.
Chelonian
Posso inserir, mas não posso excluir.
Wennie
10

Eu tive esse problema agora, usando um banco de dados SQLite em um servidor remoto, armazenado em uma montagem NFS. O SQLite não conseguiu obter um bloqueio após a falha da sessão do shell remoto que usei enquanto o banco de dados estava aberto.

As receitas de recuperação sugeridas acima não funcionaram para mim (incluindo a idéia de primeiro mover e depois copiar o banco de dados). Mas, depois de copiá-lo para um sistema não NFS, o banco de dados se tornou utilizável e não parece que os dados foram perdidos.

jogojapan
fonte
9

Meu bloqueio foi causado pelo travamento do sistema e não por um processo interrompido. Para resolver isso, simplesmente renomeei o arquivo e o copiei novamente para o nome e localização originais.

Usando um shell linux que seria ...

mv mydata.db temp.db
cp temp.db mydata.db
Ben L
fonte
solução muito fácil, resolvendo meu problema de um banco de dados bloqueado em uma unidade de rede.
Maverick2805
7

Eu adicionei " Pooling=true" à string de conexão e funcionou.

user1900210
fonte
4

Achei a documentação dos vários estados de bloqueio no SQLite muito útil. Michael, se você pode executar leituras, mas não pode executar gravações no banco de dados, isso significa que um processo obteve um bloqueio RESERVADO no banco de dados, mas ainda não executou a gravação. Se você estiver usando o SQLite3, há um novo bloqueio chamado PENDING, no qual não são permitidos mais processos, mas as conexões existentes podem ainda executar leituras; portanto, se esse for o problema, você deve examinar isso.

Kyle Cronin
fonte
4

Este erro pode ser gerado se o arquivo estiver em uma pasta remota, como uma pasta compartilhada. Mudei o banco de dados para um diretório local e funcionou perfeitamente.

Zequez
fonte
3

Eu tenho esse problema dentro do aplicativo, que acessa o SQLite a partir de 2 conexões - uma era somente leitura e a segunda para gravação e leitura. Parece que a conexão somente leitura bloqueou a gravação da segunda conexão. Por fim, verifica-se que é necessário finalizar ou, pelo menos, redefinir as instruções preparadas IMEDIATAMENTE após o uso. Até que a instrução preparada seja aberta, ela causou um bloqueio no banco de dados para gravação.

NÃO ESQUEÇA DE CHAMAR:

sqlite_reset(xxx);

ou

sqlite_finalize(xxx);
Mike Keskinov
fonte
3

Algumas funções, como INDEX'ing, podem demorar muito tempo - e bloqueiam todo o banco de dados enquanto ele é executado. Em casos como esse, talvez nem use o arquivo de diário!

Portanto, a melhor / única maneira de verificar se o seu banco de dados está bloqueado porque um processo está gravando ATIVAMENTE (e, portanto, você deve deixá-lo em paz até a conclusão de sua operação) é no md5 (ou md5sum em alguns sistemas) o arquivo duas vezes . Se você obtiver uma soma de verificação diferente, o banco de dados está sendo gravado e, na verdade, você REALMENTE NÃO deseja matar -9 nesse processo, pois pode acabar facilmente com uma tabela / banco de dados corrompidos.

Vou reiterar, porque é importante - a solução NÃO é encontrar o programa de bloqueio e matá-lo - é descobrir se o banco de dados possui um bloqueio de gravação por um bom motivo, e partir daí. Às vezes, a solução correta é apenas uma pausa para o café.

A única maneira de criar essa situação bloqueada, mas não sendo gravada é se o seu programa for executado BEGIN EXCLUSIVE, porque ele queria fazer algumas alterações na tabela ou algo assim, então, por qualquer motivo, nunca envia ENDdepois e o processo nunca termina . Todas as três condições atendidas são altamente improváveis ​​em qualquer código corretamente escrito e, como tal, 99 vezes em 100 quando alguém deseja matar -9 seu processo de bloqueio, o processo de bloqueio está realmente bloqueando seu banco de dados por um bom motivo. Os programadores normalmente não adicionam a BEGIN EXCLUSIVEcondição, a menos que realmente precisem, porque isso impede a concorrência e aumenta as reclamações dos usuários. O próprio SQLite o adiciona apenas quando realmente é necessário (como na indexação).

Finalmente, o status 'bloqueado' não existe DENTRO do arquivo, como várias respostas indicaram - ele reside no kernel do sistema operacional. O processo executado BEGIN EXCLUSIVEsolicitou ao sistema operacional um bloqueio para ser colocado no arquivo. Mesmo que seu processo exclusivo tenha falhado, seu sistema operacional será capaz de descobrir se deve manter o bloqueio do arquivo ou não !! Não é possível terminar com um banco de dados bloqueado, mas nenhum processo está bloqueando-o ativamente! Quando se trata de ver qual processo está bloqueando o arquivo, normalmente é melhor usar lsof do que o fusor (esta é uma boa demonstração do porquê: /unix/94316/fuser-vs-lsof- para verificar os arquivos em uso ). Como alternativa, se você possui o DTrace (OSX), pode usar o iosnoop no arquivo.

JJ
fonte
2

Acabei de acontecer algo parecido comigo - meu aplicativo da Web conseguiu ler o banco de dados, mas não conseguiu realizar inserções ou atualizações. Uma reinicialização do Apache resolveu o problema pelo menos temporariamente.

Seria bom, no entanto, ser capaz de rastrear a causa raiz.

Michael Cox
fonte
2

O comando lsof no meu ambiente Linux me ajudou a descobrir que havia um processo interrompido para manter o arquivo aberto.
Matou o processo e o problema foi resolvido.

PinkSheep
fonte
2

Deve ser um problema interno do banco de dados ...
Para mim, ele se manifestou depois de tentar navegar no banco de dados com o "SQLite manager" ...
Então, se você não encontrar outro processo, conecte-se ao banco de dados e não consiga corrigi-lo, tente esta solução radical:

  1. Forneça para exportar suas tabelas (você pode usar o "SQLite manager" no Firefox)
  2. Se a migração alterar o esquema do banco de dados, exclua a última migração com falha
  3. Renomeie seu arquivo "database.sqlite"
  4. Execute "rake db: migrate" para criar um novo banco de dados funcional
  5. Forneça para conceder as permissões corretas ao banco de dados para importação da tabela
  6. Importe suas tabelas de backup
  7. Escreva a nova migração
  8. Execute-o com " rake db:migrate"
Davide Ganz
fonte
1

Eu encontrei esse mesmo problema no Mac OS X 10.5.7 executando scripts Python a partir de uma sessão do terminal. Mesmo que eu tivesse parado os scripts e a janela do terminal estivesse no prompt de comando, isso causaria esse erro na próxima vez em que fosse executado. A solução foi fechar a janela do terminal e abri-la novamente. Não faz sentido para mim, mas funcionou.

Shawn Swaner
fonte
1

Eu apenas tive o mesmo erro. Após 5 minets no google, descobri que não fechei um shell que estava usando o db. Basta fechá-lo e tente novamente;)

Fluxo
fonte
1

Eu tive o mesmo problema. Aparentemente, a função de reversão parece substituir o arquivo db pelo diário, que é o mesmo que o arquivo db, mas sem a alteração mais recente. Eu implementei isso no meu código abaixo e ele está funcionando bem desde então, enquanto antes meu código ficava preso no loop enquanto o banco de dados fica bloqueado.

Espero que isto ajude

meu código 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 )
Jay
fonte
1

Um motivo comum para obter essa exceção é quando você está tentando executar uma operação de gravação enquanto mantém os recursos para uma operação de leitura. Por exemplo, se você selecionar a partir de uma tabela e tentar atualizar algo que você selecionou sem fechar primeiro o ResultSet.

Martin Carney
fonte
1

Eu também estava tendo erros "o banco de dados está bloqueado" em um aplicativo multithread, que parece ser o código de resultado SQLITE_BUSY , e resolvi-o com a configuração de sqlite3_busy_timeout para algo adequadamente longo como 30000.

(Em uma nota lateral, como é estranho que em uma pergunta de 7 anos ninguém tenha descoberto isso! SQLite é realmente um projeto peculiar e surpreendente ...)

Stijn Sanders
fonte
1

Antes de ir para a opção de reinicialização, vale a pena ver se você encontra o usuário do banco de dados sqlite.

No Linux, pode-se empregar fuserpara esse fim:

$ fuser database.db

$ fuser database.db-journal

No meu caso, recebi a seguinte resposta:

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

O que mostrou que eu tinha outro programa Python com o pid 3556 (manage.py) usando o banco de dados.

Philip Clarke
fonte
1

Uma pergunta antiga, com muitas respostas, eis as etapas que segui recentemente, lendo as respostas acima, mas, no meu caso, o problema ocorreu devido ao compartilhamento de recursos CIFs. Este caso não foi relatado anteriormente, por isso espero que ajude alguém.

  • Verifique se nenhuma conexão foi deixada aberta no seu código java.
  • Verifique se nenhum outro processo está usando seu arquivo db SQLite com lsof.
  • Verifique se o proprietário do usuário do seu processo jvm em execução tem permissões de r / w sobre o arquivo.
  • Tente forçar o modo de bloqueio na abertura da conexão com

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

Se você estiver usando o arquivo db SQLite em uma pasta compartilhada NFS, verifique este ponto do faq do SQLite e revise suas opções de configuração de montagem para garantir que você evite bloqueios, conforme descrito aqui :

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

Eu recebi esse erro em um cenário um pouco diferente dos descritos aqui.

O banco de dados SQLite estava em um sistema de arquivos NFS compartilhado por 3 servidores. Em dois dos servidores, eu era capaz de executar consultas no banco de dados com êxito, no terceiro, pensei que estava recebendo a mensagem "o banco de dados está bloqueado".

A coisa com esta terceira máquina era que ela não tinha mais espaço /var. Toda vez que eu tentava executar uma consulta em QUALQUER banco de dados SQLite localizado neste sistema de arquivos, recebia a mensagem "o banco de dados está bloqueado" e também esse erro nos logs:

8 de agosto 10:33:38 kernel server01: lockd: não pode monitorar 172.22.84.87

E este também:

8 de agosto 10:33:38 server01 rpc.statd [7430]: Falha ao inserir: writing /var/lib/nfs/statd/sm/other.server.name.com: Não há espaço no dispositivo 8 de agosto 10:33: 38 server01 rpc.statd [7430]: STAT_FAIL para server01 para SM_MON de 172.22.84.87

Depois que a situação espacial foi resolvida, tudo voltou ao normal.

ederribeiro
fonte
1

Se você estiver tentando desbloquear o banco de dados do Chrome para visualizá-lo com o SQLite , basta desligar o Chrome.

janelas

%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
fonte
0

Dos seus comentários anteriores, você disse que um arquivo -journal estava presente.

Isso pode significar que você abriu e (EXCLUSIVO?) A transação e ainda não confirmou os dados. Seu programa ou algum outro processo deixou o diário para trás?

Reiniciar o processo sqlite examinará o arquivo de diário, limpará as ações não confirmadas e removerá o arquivo -journal.


fonte
0

Como Seun Osewa disse, às vezes um processo de zumbi fica no terminal com uma trava, mesmo que você não considere possível. Seu script é executado, trava e você volta ao prompt, mas há um processo de zumbi gerado em algum lugar por uma chamada de biblioteca, e esse processo tem o bloqueio.

Fechar o terminal em que você estava (no OSX) pode funcionar. A reinicialização funcionará. Você pode procurar por processos "python" (por exemplo) que não estão fazendo nada e matá-los.

melancólico
fonte
0

você pode tentar o seguinte: .timeout 100para definir o tempo limite. Não sei o que acontece na linha de comando, mas no C # .Net quando faço isso: "UPDATE table-name SET column-name = value;"Recebo o banco de dados bloqueado, mas isso funciona "UPDATE table-name SET column-name = value"bem.

Parece que quando você adiciona ;, o sqlite procurará mais comandos.

Dzung Nguyen
fonte