C# 即使在连接关闭后,SQLite也会保持数据库锁定

C# 即使在连接关闭后,SQLite也会保持数据库锁定,c#,sqlite,system.data.sqlite,C#,Sqlite,System.data.sqlite,我正在ASP.NET应用程序(framework 4.0)中使用System.Data.SQLite提供程序。 我遇到的问题是,当我在SQLite数据库的表中插入某些内容时,数据库会被锁定,即使在释放连接后,锁也不会被释放 尝试访问该文件时,错误为:“进程无法访问文件‘catalog.sqlite’,因为它正被另一个进程使用。” 我的代码非常简单,我打开连接,从SQLServer数据库中读取一些数据,将这些数据插入SQLite(通过SQLiteDataAdapter),然后关闭连接,为了安全起见

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

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

我的代码非常简单,我打开连接,从SQLServer数据库中读取一些数据,将这些数据插入SQLite(通过SQLiteDataAdapter),然后关闭连接,为了安全起见处理一切。但是,当我用数据填充文件后尝试压缩文件时,仍然会出现错误

我在这里读过关于StackOverflow的各种建议,但都没有帮助解决这个问题(关闭杀毒软件、更改事务模型、在压缩文件前等待几秒钟、将所有插入调用包装到事务中等等)。但是没有一个有助于解决这个问题

也许ASP.NET有一些特定的功能(多线程是一个问题?即使我在一台开发机器上测试它,其中只有一个函数调用,没有并发性?)


作为补充说明,我尝试避免使用DataTable和SQLiteDataAdapter,只直接使用SQLiteCommand,这样做很有吸引力。当然,我可以继续将查询构建为字符串,而不是使用数据适配器,但当构建了一个框架来实现这一点时,我觉得有点尴尬。

我在使用数据适配器时也遇到了同样的问题使用设计器生成的ts/tableadapters随
System.Data.Sqlite.dll
1.0.82.0版一起提供--关闭连接后,我们无法使用
System.IO.FileStream
读取数据库文件。我正确地处理了连接和tableadapters,并且没有使用连接池

根据我的第一次搜索(例如和),这似乎是库本身的一个问题——要么是对象没有正确释放,要么是池问题(我没有使用)

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

然后我打开生成的TableAdapters,我看到没有实现
Dispose
方法——因此实际上创建的命令没有被释放。我实现了它,处理了所有命令,我没有遇到任何问题

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

//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();
            }
        }
    }
}
  • 关于
    TableAdapter
    Dispose
    调用的实现:最好将其放在分部类中,这样数据集重新生成不会影响此代码(以及可能需要添加的任何其他代码)


  • 我也有同样的问题。我的场景是在获取SQLite数据库文件中的数据后,我想删除该文件,但它总是抛出一个错误“…由其他进程使用”。即使我处理SqliteConnection或SqliteCommand,错误仍然会发生。我已通过调用
    GC.Collect()
    修复了该错误

    代码片段

    public void DisposeSQLite()
    {
        SQLiteConnection.Dispose();
        SQLiteCommand.Dispose();
    
        GC.Collect();
    }
    

    希望这有帮助。

    在我的例子中,我创建了
    SQLiteCommand
    对象,但没有显式地处理它们

    var command = connection.CreateCommand();
    command.CommandText = commandText;
    value = command.ExecuteScalar();
    
    我使用语句将命令包装在一个
    中,它解决了我的问题

    static public class SqliteExtensions
    {
        public static object ExecuteScalar(this SQLiteConnection connection, string commandText)
        {
            // Added using
            using (var command = connection.CreateCommand())
            {
                command.CommandText = commandText;
                return command.ExecuteScalar();
            }
        }
    }
    
    那么你可以这样使用它

    connection.ExecuteScalar(commandText);
    

    我发现edymtt关于责怪TableAdapter/数据集的回答是正确的,但我没有在每次重新生成TableAdapter代码文件时修改它,而是找到了另一种解决方案:手动调用TableAdapter的子元素上的.Dispose。(在.NET 4.5中,最新的SQLite 1.0.86)


    在大多数情况下,如果不正确处理读卡器和命令,就会出现问题。在某些情况下,命令和读卡器不会正确处理

    场景1:如果您正在运行一个布尔函数。在到达结果之前,finally块中的代码将不会异常。如果您要在执行代码时评估函数isDataExists的结果,如果它符合结果,这将是一个大问题

        if(isDataExists){
            // execute some code
        }
    
    正在评估的功能

        public bool isDataExists(string sql)
        {
            try
            {
                OpenConnection();
                SQLiteCommand cmd = new SQLiteCommand(sql, connection);
                reader = cmd.ExecuteReader();
                if (reader != null && reader.Read())
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception expMsg)
            {
                //Exception
            }
            finally
            {
                if (reader != null)
                {
                    reader.Dispose();
                }
                CloseConnection();
            }
            return true;
        }
    
    解决方案:按如下方式在try块中处理读卡器和命令

                OpenConnection();
                SQLiteCommand cmd = new SQLiteCommand(sql, connection);
                reader = cmd.ExecuteReader();
                if (reader != null && reader.Read())
                {
                    cmd.Dispose();
                    CloseConnection();
                    return true;
                }
                else
                {
                    cmd.Dispose();
                    CloseConnection();
                    return false;
                }
    
    最后处理读卡器和命令,以防出错

            finally
            {
                if (reader != null)
                {
                    reader.Dispose();
                }
                CloseConnection();
            }
    

    当我遇到这个错误时,这是我在谷歌上找到的最好的搜索结果之一。但是,没有一个回复对我有帮助,所以在进行了更多的搜索和谷歌搜索之后,我找到了这个代码,它可以从

    但是,我根本不需要使用NuGet。我的程序所做的是每次打开服务器时从服务器下载一个db文件。然后,如果用户更新了该db,则将上载该db,以便所有人在下次打开同一程序时都能获得。我收到的错误是,在更新本地文件并尝试上载后,该文件正在使用中它可以连接到我们的SharePoint。现在它工作正常

    Public Function sqLiteGetDataTable(sql As String) As DataTable
        Dim dt As New DataTable()
        Using cnn = New SQLiteConnection(dbConnection)
            cnn.Open()
            Using cmd As SQLiteCommand = cnn.CreateCommand()
                cmd.CommandText = sql
                Using reader As System.Data.SQLite.SQLiteDataReader = cmd.ExecuteReader()
                    dt.Load(reader)
                    reader.Dispose()
                End Using
                cmd.Dispose()
            End Using
            If cnn.State <> System.Data.ConnectionState.Closed Then
                cnn.Close()
            End If
            cnn.Dispose()
        End Using
        Return dt
    End Function
    
    公共函数sqLiteGetDataTable(sql作为字符串)作为DataTable
    Dim dt作为新数据表()
    使用cnn=新的SQLiteConnection(dbConnection)
    cnn.Open()
    使用cmd作为SQLiteCommand=cnn.CreateCommand()
    cmd.CommandText=sql
    将读卡器用作System.Data.SQLite.SQLiteDataReader=cmd.ExecuteReader()
    dt.负载(读卡器)
    reader.Dispose()
    终点
    
            finally
            {
                if (reader != null)
                {
                    reader.Dispose();
                }
                CloseConnection();
            }
    
    Public Function sqLiteGetDataTable(sql As String) As DataTable
        Dim dt As New DataTable()
        Using cnn = New SQLiteConnection(dbConnection)
            cnn.Open()
            Using cmd As SQLiteCommand = cnn.CreateCommand()
                cmd.CommandText = sql
                Using reader As System.Data.SQLite.SQLiteDataReader = cmd.ExecuteReader()
                    dt.Load(reader)
                    reader.Dispose()
                End Using
                cmd.Dispose()
            End Using
            If cnn.State <> System.Data.ConnectionState.Closed Then
                cnn.Close()
            End If
            cnn.Dispose()
        End Using
        Return dt
    End Function
    
    using(var connection = new SqliteConnection("source.db"))
    {
        connection.Open();
        using(var command = connection.CreateCommand("select..."))
        {
            command.Execute...
        }
    }
    
    using(var connection = new SqliteConnection("source.db"))
    {
        connection.Open();
        using(var command = connection.CreateCommand("select..."))
        {
            command.Execute...
            connection.Close();
        }
    }
    
                    SQLiteConnectionStringBuilder builder = new SQLiteConnectionStringBuilder
                    {
                        Pooling = true
                    };