gpt4 book ai didi

c# - SQLite 即使在连接关闭后仍保持数据库锁定

转载 作者:IT王子 更新时间:2023-10-29 04:02:06 27 4
gpt4 key购买 nike

我在 ASP.NET 应用程序(框架 4.0)中使用 System.Data.SQLite 提供程序。我遇到的问题是,当我在 SQLite 数据库的表中插入某些内容时,数据库被锁定并且即使在处理连接后也不会释放锁定。

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

我的代码非常简单,我打开连接,从 SQLServer 数据库中读取一些数据,将该数据插入 SQLite(通过 SQLiteDataAdapter),然后关闭连接并处理所有内容以确保安全。但是,当我在用数据填充文件后尝试压缩文件时,仍然会遇到该错误。

我在 StackOverflow 上阅读了各种建议,但没有一个有助于解决问题(关闭防病毒软件、更改事务模型、等待几秒钟然后压缩文件、将所有插入调用包装到交易等。但都没有帮助解决这个问题。

也许有一些特定于 ASP.NET 的东西(多线程是问题?即使我在一台开发机器上测试它,那里只有一个对该函数的调用并且没有并发?)

作为旁注,我尝试避免使用 DataTable 和 SQLiteDataAdapter 并直接仅使用 SQLiteCommand,这样就很有魅力了。当然,我可以继续将查询构建为字符串,而不是使用数据适配器,但是当构建了一个框架来执行此操作时,我觉得有点尴尬。

最佳答案

我在使用 System.Data.Sqlite.dll 版本 1.0.82.0 附带的设计器生成的数据集/表适配器时遇到了同样的问题——关闭连接后我们无法读取数据库使用 System.IO.FileStream 的文件。我正确地处理了连接和表适配器,并且没有使用连接池。

根据我的第一次搜索(例如 thisthis thread ),库本身似乎存在问题——对象未正确释放和/或池问题(我不使用)。

阅读您的问题后,我尝试仅使用 SQLiteCommand 对象来复制问题,但我发现当您不处理它们时就会出现问题。 更新 2012-11-27 19:37 UTC:this ticket 进一步证实了这一点对于 System.Data.SQLite,开发人员在其中解释说“所有与连接关联的 SQLiteCommand 和 SQLiteDataReader 对象 [应该] 正确处理”。

然后我重新打开生成的 TableAdapter,我看到没有执行 Dispose 方法——所以实际上创建的命令没有被释放。我实现了它,负责处理所有命令,我没有遇到任何问题。

这是 C# 中的代码,希望对您有所帮助。请注意,代码是从 original in Visual Basic 转换而来的,因此预计会出现一些转换错误。

//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-07-05 17:36 UTC gorogm's answer强调两件重要的事情:

  • 根据 changelog在 System.Data.SQLite 的官方网站上,从版本 1.0.84.0 开始,应该不需要上面的代码,因为库会处理这个。我没有测试过这个,但在最坏的情况下你只需要这个片段:

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

    this.Adapter.Dispose();
    }
  • 关于 TableAdapterDispose 调用的实现:最好把它放在分部类中,这样数据集重新生成就不会影响此代码(以及您可能需要添加的任何其他代码)。

关于c# - SQLite 即使在连接关闭后仍保持数据库锁定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12532729/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com