SQLite的保持甚至锁定数据库的连接关闭后 [英] SQLite keeps the database locked even after the connection is closed

查看:465
本文介绍了SQLite的保持甚至锁定数据库的连接关闭后的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用System.Data.SQLite提供者在ASP.NET应用程序(框架4.0)。
我遇到的问题是,当我在SQLite数据库表中插入一些东西,数据库被锁定,连接配置即使在锁没有被释放。

I'm using System.Data.SQLite provider in an ASP.NET application (framework 4.0). The issue I'm running into is that when I INSERT something in a table in the SQLite database, the database gets locked and the lock isn't being released even after the connection is disposed.

当试图访问该文件,错误是:该进程无法访问该文件'catalog.sqlite',因为它正被另一个进程使用。

When trying to access the file, the error is: "The process cannot access the file 'catalog.sqlite' because it is being used by another process."

我的code为pretty简单,我打开连接,从一个SQLServer数据库中读取一些数据,这些数据插入到SQLite的(通过SQLiteDataAdapter),然后关闭连接和处理一切都只是要上安全方面。但是,我得到这个错误,当我尝试压缩文件它正在与填充数据后。

My code is pretty straightforward, I open the connection, read some data from a SQLServer database, insert that data into SQLite (through SQLiteDataAdapter) and then close the connection and dispose everything just to be on the safe side. But still, I get that error when I try to zip the file after it's being populated with the data.

我读过都挺这里建议在计算器上,但没有人帮助解决问题(关闭杀毒软件,改变了交易模式,压缩和解了文件之前,等待几秒钟,所有包裹插入调用到一次交易,等等。但没有帮助解决这一问题。

I've read all kind of suggestions here on StackOverflow but none of them has helped solving the problem (turning off the antivirus, changing the transaction model, waiting a few seconds before zipping up the file, wrapping all the insert calls into a transaction, etc.. but none has helped solving this issue.

也许有一些具体的事情到ASP.NET(多线程是问题?即使我在开发机器那里只有一个针对该功能没有并发通话测试它?)

Maybe there's something specific to ASP.NET (multithreading being the issue? Even though I'm testing it on a development machine where there's only one call to that function and no concurrency?)

作为一个方面说明,我试图避免的DataTable和SQLiteDataAdapter只使用SQLiteCommand直接和它的工作方式一个魅力。当然,我可以保持我的建设作为查询字符串,而不是使用数据适配器,但我有点觉得有点尴尬时,有内置做到这一点的框架。

As a side note, I tried avoiding DataTable and SQLiteDataAdapter and using only SQLiteCommand directly and that way it works a charm. Of course I can keep building my queries as strings instead of using the data adapters, but I kind of find it a bit awkward when there's a framework built to do that.

推荐答案

我不得不使用带有附带设计器生成数据集/ TableAdapter的同样的问题 System.Data.Sqlite.dll 1.0.82.0版本 - 关闭我们无法读取使用 System.IO.FileStream 数据库文件的连接之后。我是正确处理两者的连接和TableAdapter的,我并没有使用连接池。

I had the same problem using the datasets/tableadapters generated with the designer shipped with System.Data.Sqlite.dll version 1.0.82.0 -- after closing the connection we were unable to read the database file using System.IO.FileStream. I was disposing correctly both connection and tableadapters and I was not using connection pooling.

据我的第一个搜索(例如<一个href=\"http://stackoverflow.com/questions/5994141/checking-if-table-exists-keeping-connection-open-in-sqlite\">this和<一个href=\"http://stackoverflow.com/questions/8511901/system-data-sqlite-close-not-releasing-database-file\">this这似乎在图书馆本身的问题线程) - 无论是对象不正确地释放和/或池的问题(我不使用)

According to my first searches (for example this and this thread) that seemed a problem in the library itself -- either objects not correctly released and/or pooling issues (which I don't use).

阅读您的问题后,我试图复制使用问题只SQLiteCommand对象,我发现,问题就出现了,当你不处理它们。 更新2012年11月27日19:37 UTC :这是由这对于System.Data.SQLite票,其中开发人员解释说,与连接相关联的所有的SQLiteCommand和SQLiteDataReader对象[应]妥善处理。

After reading your question I tried to replicate the problem using only SQLiteCommand objects and I found that the problem arises when you don't dispose them. Update 2012-11-27 19:37 UTC: this is further confirmed by this ticket for System.Data.SQLite, in which a developer explains that "all SQLiteCommand and SQLiteDataReader objects associated with the connection [should be] properly disposed".

我再重新打开生成的TableAdapter的,我看到,没有了的Dispose 方法的实现 - 所以其实创建的命令并未处理。我实现它,以处理所有的命令照顾,和我有没有问题。

I then turned back on the generated TableAdapters and I saw that there was no implementation of the Dispose method -- so in fact the created commands were not disposed. I implemented it, taking care of disposing all the commands, and I have got no problem.

下面是在C#中code,希望这有助于。请注意,code都在Visual Basic中中的原来的转换,所以我们期待一些转换错误。

Here's the code in C#, hope this helps. Please note that the code is converted from the original in Visual Basic, so expect some conversion errors.

//In Table Adapter    
protected override void Dispose(bool disposing)
{
   base.Dispose(disposing);

    Common.DisposeTableAdapter(disposing, _adapter, _commandCollection);
}

public static class Common
{
    /// <summary>
    /// Disposes a TableAdapter generated by SQLite Designer
    /// </summary>
    /// <param name="disposing"></param>
    /// <param name="adapter"></param>
    /// <param name="commandCollection"></param>
    /// <remarks>You must dispose all the command,
    /// otherwise the file remains locked and cannot be accessed
    /// (for example, for reading or deletion)</remarks>
    public static void DisposeTableAdapter(
        bool disposing,
        System.Data.SQLite.SQLiteDataAdapter adapter,
        IEnumerable<System.Data.SQLite.SQLiteCommand> commandCollection)
    {
        if (disposing) {
            DisposeSQLiteTableAdapter(adapter);

            foreach (object currentCommand_loopVariable in commandCollection)
            {
                currentCommand = currentCommand_loopVariable;
                currentCommand.Dispose();
            }
        }
    }

    public static void DisposeSQLiteTableAdapter(
            System.Data.SQLite.SQLiteDataAdapter adapter)
    {
        if (adapter != null) {
            DisposeSQLiteTableAdapterCommands(adapter);

            adapter.Dispose();
        }
    }

    public static void DisposeSQLiteTableAdapterCommands(
            System.Data.SQLite.SQLiteDataAdapter adapter)
    {
        foreach (object currentCommand_loopVariable in {
            adapter.UpdateCommand,
            adapter.InsertCommand,
            adapter.DeleteCommand,
            adapter.SelectCommand})
        {
            currentCommand = currentCommand_loopVariable;
            if (currentCommand != null) {
                currentCommand.Dispose();
            }
        }
    }
}

更新2013年7月5日17:36 UTC gorogm的回答突出了两个重要的事情

Update 2013-07-05 17:36 UTC gorogm's answer highlights two important things:


  • 根据的changelog 在官方网站System.Data.SQLite,从版本1.0.84.0上述code首发应该没有必要,因为库会处理这件事。我没有测试过这一点,但在最坏的情况下,你只需要这个片段:

  • according to the changelog on the official site of System.Data.SQLite, starting from version 1.0.84.0 the above code should not be needed, since the library takes care of this. I haven't tested this, but in the worst case you only need this snippet:

//In Table Adapter    
protected override void Dispose(bool disposing)
{
  base.Dispose(disposing);

  this.Adapter.Dispose();
}


  • 有关的的TableAdapter 的Dispose 调用的实现:它是更好地把这个在部分类,让数据恢复不影响本code(以及任何额外的code,你可能需要添加)。

  • about the implementation of the Dispose call of the TableAdapter: it is is better to put this in a partial class, so that a dataset regeneration does not affected this code (and any additional code you may need to add).

    这篇关于SQLite的保持甚至锁定数据库的连接关闭后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆