Estou tendo problemas para fechar meu banco de dados antes de tentar excluir o arquivo. O código é apenas
myconnection.Close();
File.Delete(filename);
E o Delete lança uma exceção de que o arquivo ainda está em uso. Tentei novamente Delete () no depurador após alguns minutos, portanto, não é um problema de tempo.
Eu tenho o código de transação, mas ele não é executado antes da chamada Close (). Portanto, tenho quase certeza de que não é uma transação aberta. Os comandos sql entre abrir e fechar são apenas seleções.
ProcMon mostra meu programa e meu antivírus olhando o arquivo de banco de dados. Ele não mostra meu programa liberando o arquivo db após o close ().
Visual Studio 2010, C #, System.Data.SQLite versão 1.0.77.0, Win7
Eu vi um bug de dois anos assim, mas o changelog diz que foi consertado.
Há mais alguma coisa que eu possa verificar? Existe uma maneira de obter uma lista de quaisquer comandos ou transações abertas?
Novo código funcional:
db.Close();
GC.Collect(); // yes, really release the db
bool worked = false;
int tries = 1;
while ((tries < 4) && (!worked))
{
try
{
Thread.Sleep(tries * 100);
File.Delete(filename);
worked = true;
}
catch (IOException e) // delete only throws this on locking
{
tries++;
}
}
if (!worked)
throw new IOException("Unable to close file" + filename);
fonte
SQLiteAsyncConnection.ResetPool()
, consulte este problema para obter detalhes.Respostas:
Encontrei o mesmo problema há algum tempo enquanto escrevia uma camada de abstração de banco de dados para C # e na verdade nunca descobri qual era o problema. Acabei lançando uma exceção quando você tentou excluir um banco de dados SQLite usando minha biblioteca.
De qualquer forma, esta tarde eu estava examinando tudo de novo e pensei em tentar descobrir por que estava fazendo isso de uma vez por todas, então aqui está o que descobri até agora.
O que acontece quando você chama
SQLiteConnection.Close()
é que (junto com uma série de verificações e outras coisas) oSQLiteConnectionHandle
que aponta para a instância do banco de dados SQLite é descartado. Isso é feito por meio de uma chamada paraSQLiteConnectionHandle.Dispose()
, no entanto, isso não libera realmente o ponteiro até que o Coletor de lixo do CLR execute alguma coleta de lixo. ComoSQLiteConnectionHandle
substitui aCriticalHandle.ReleaseHandle()
função a ser chamadasqlite3_close_interop()
(por meio de outra função), isso não fecha o banco de dados.Do meu ponto de vista, esta é uma maneira muito ruim de fazer as coisas, já que o programador não tem certeza de quando o banco de dados será fechado, mas é assim que foi feito, então acho que temos que conviver com isso por enquanto ou cometer algumas alterações em System.Data.SQLite. Quaisquer voluntários são bem-vindos, infelizmente não tenho tempo para fazê-lo antes do próximo ano.
TL; DR A solução é forçar um GC após sua chamada para
SQLiteConnection.Close()
e antes de sua chamada paraFile.Delete()
.Aqui está o código de exemplo:
Boa sorte com isso e espero que ajude
fonte
Simplesmente
GC.Collect()
não funcionou para mim.Tive que adicionar
GC.WaitForPendingFinalizers()
depoisGC.Collect()
para prosseguir com a exclusão do arquivo.fonte
GC.Collect()
apenas inicia uma coleta de lixo que é assíncrona, então, para ter certeza de que tudo foi limpo, você terá que esperar por isso explicitamente.No meu caso, eu estava criando
SQLiteCommand
objetos sem descartá-los explicitamente.Envolvi meu comando em uma
using
declaração e resolveu meu problema.Então, é muito mais fácil executar comandos também.
fonte
Tive um problema semelhante, embora a solução do coletor de lixo não o tenha corrigido.
Encontrado descartar
SQLiteCommand
eSQLiteDataReader
objetos após o uso me salvou usando o coletor de lixo em tudo.fonte
SQLiteCommand
mesmo se você reciclar umaSQLiteCommand
variável posteriormente.command.Dispose();
a todos osSQLiteCommand
que foram executados..Dispose()
) outros objetos como SQLiteTransaction, se houver.O seguinte funcionou para mim:
Mais informações : As conexões são agrupadas pelo SQLite para melhorar o desempenho. Isso significa que quando você chama o método Close em um objeto de conexão, a conexão com o banco de dados ainda pode estar ativa (em segundo plano) para que o próximo método Open se torne mais rápido. você não quer mais uma nova conexão, chamar ClearAllPools fecha todas as conexões que estão ativas em segundo plano e os identificadores de arquivo para o arquivo db são liberados. Então, o arquivo db pode ser removido, excluído ou usado por outro processo.
fonte
SQLiteConnectionPool.Shared.Reset()
. Isso fechará todas as conexões abertas. Em particular, esta é uma solução se você usar oSQLiteAsyncConnection
que não possui umClose()
método.Eu estava tendo um problema semelhante, tentei a solução com
GC.Collect
, mas, conforme observado, pode levar muito tempo para que o arquivo não seja bloqueado.Eu encontrei uma solução alternativa que envolve o descarte dos
SQLiteCommand
s subjacentes nos TableAdapters, consulte esta resposta para obter informações adicionais.fonte
Tente isto ... este tenta todos os códigos acima ... funcionou para mim
espero que ajude
fonte
Tenho tido o mesmo problema com EF e
System.Data.Sqlite
.Para mim, descobri
SQLiteConnection.ClearAllPools()
eGC.Collect()
reduziria a frequência com que o bloqueio de arquivos acontecia, mas ainda acontecia ocasionalmente (cerca de 1% das vezes).Estive investigando e parece que alguns
SQLiteCommand
s que o EF cria não são descartados e ainda têm sua propriedade Connection definida para a conexão fechada. Tentei descartá-los, mas o Entity Framework lançaria uma exceção durante a próximaDbContext
leitura - parece que o EF às vezes ainda os usa após o fechamento da conexão.Minha solução foi garantir que a propriedade Connection fosse definida para
Null
quando a conexão fosse encerrada nessesSQLiteCommand
s. Isso parece ser suficiente para liberar o bloqueio do arquivo. Estive testando o código abaixo e não vi nenhum problema de bloqueio de arquivo após alguns milhares de testes:Para usar, basta chamar
ClearSQLiteCommandConnectionHelper.Initialise();
no início do carregamento do aplicativo. Isso manterá uma lista de comandos ativos e definirá sua conexão paraNull
quando eles apontarem para uma conexão que está fechada.fonte
Usar
GC.WaitForPendingFinalizers()
Exemplo:
fonte
Teve um problema semelhante. Ligar para o Garbage Collector não me ajudou. Depois, encontrei uma maneira de resolver o problema
O autor também escreveu que fez consultas SELECT ao banco de dados antes de tentar excluí-lo. Eu tenho a mesma situação.
Eu tenho o seguinte código:
Além disso, não preciso fechar a conexão com o banco de dados e chamar o Garbage Collector. Tudo que eu tive que fazer é fechar o leitor que foi criado durante a execução da consulta SELECT
fonte
Acredito que a chamada para
SQLite.SQLiteConnection.ClearAllPools()
é a solução mais limpa. Pelo que eu sei, não é adequado chamar manualmenteGC.Collect()
no ambiente WPF. Embora eu não tenha percebido o problema até ter atualizado paraSystem.Data.SQLite
1.0.99.0 em 3/2016fonte
Talvez você nem precise lidar com GC. Por favor, verifique se tudo
sqlite3_prepare
está finalizado.Para cada um
sqlite3_prepare
, você precisa de um correspondentesqlite3_finalize
.Se você não finalizar corretamente,
sqlite3_close
não fechará a conexão.fonte
Eu estava lutando com um problema semelhante. Que vergonha ... finalmente percebi que o Reader não estava fechado. Por alguma razão, pensei que o Reader será fechado quando a conexão correspondente for fechada. Obviamente, GC.Collect () não funcionou para mim.
Envolver o Reader com a instrução "using: também é uma boa ideia. Aqui está um código de teste rápido.
fonte
Eu estava usando SQLite 1.0.101.0 com EF6 e tendo problemas com o arquivo sendo bloqueado após todas as conexões e entidades descartadas.
Isso piorou com atualizações do EF mantendo o banco de dados bloqueado após a conclusão. GC.Collect () foi a única solução alternativa que ajudou e eu estava começando a me desesperar.
Em desespero, experimentei o ClearSQLiteCommandConnectionHelper de Oliver Wickenden (veja sua resposta de 8 de julho). Fantástico. Todos os problemas de bloqueio desapareceram! Obrigado Oliver.
fonte
Esperar pelo coletor de lixo pode não liberar o banco de dados o tempo todo e isso aconteceu comigo. Quando algum tipo de Exceção ocorre no banco de dados SQLite, por exemplo, tentando inserir uma linha com valor existente para PrimaryKey, ele manterá o arquivo do banco de dados até que você o descarte. O código a seguir captura a exceção SQLite e cancela o comando problemático.
Se você não manipular as exceções de comandos problemáticos, o Garbage Collector não poderá fazer nada a respeito, porque há algumas exceções não manipuladas sobre esses comandos, portanto, não são lixo. Este método de tratamento funcionou bem para mim com a espera pelo coletor de lixo.
fonte
Isso funciona para mim, mas percebi que às vezes os arquivos de diário -wal -shm não são excluídos quando o processo é fechado. Se você deseja que o SQLite remova os arquivos -wal -shm quando todas as conexões forem fechadas, a última conexão fechada DEVE SER não somente leitura. Espero que isso ajude alguém.
fonte
Melhor resposta que funcionou para mim.
fonte