C# 即使在连接关闭后,SQLite也会保持数据库锁定
我正在ASP.NET应用程序(framework 4.0)中使用System.Data.SQLite提供程序。 我遇到的问题是,当我在SQLite数据库的表中插入某些内容时,数据库会被锁定,即使在释放连接后,锁也不会被释放 尝试访问该文件时,错误为:“进程无法访问文件‘catalog.sqlite’,因为它正被另一个进程使用。” 我的代码非常简单,我打开连接,从SQLServer数据库中读取一些数据,将这些数据插入SQLite(通过SQLiteDataAdapter),然后关闭连接,为了安全起见处理一切。但是,当我用数据填充文件后尝试压缩文件时,仍然会出现错误 我在这里读过关于StackOverflow的各种建议,但都没有帮助解决这个问题(关闭杀毒软件、更改事务模型、在压缩文件前等待几秒钟、将所有插入调用包装到事务中等等)。但是没有一个有助于解决这个问题 也许ASP.NET有一些特定的功能(多线程是一个问题?即使我在一台开发机器上测试它,其中只有一个函数调用,没有并发性?)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),然后关闭连接,为了安全起见
作为补充说明,我尝试避免使用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
};