我在我的项目中经常使用简单的DataReader命令。 为了简化它,我创建了一个函数:
Public Function DataReaderFromCommand(ByRef uCn As SQLite.SQLiteConnection, ByVal uCommandText As String) As SQLite.SQLiteDataReader
Dim nCmdSel As SQLite.SQLiteCommand = uCn.CreateCommand
With nCmdSel
.CommandText = uCommandText
End With
Dim r As SQLite.SQLiteDataReader = nCmdSel.ExecuteReader
Return r
End Function
在我的项目中,我使用它:
Using r As SQLite.SQLiteDataReader = DataReaderFromCommand(cnUser, "SELECT * FROM settings")
Do While r.Read
'do something
Loop
End Using'this should close the DataReader
在一个案例中,我需要删除我的数据库。但是这会因错误而失败"文件被另一个进程锁定"。
我试图找出问题,并且由于函数" DataReaderFromCommand"而发生锁定。
有人看到我做错了什么/是什么让数据库锁定?
我认为"结束使用"对于datareader,SQLiteCommand也会被处理掉,因此没有对数据库的进一步引用。
答案 0 :(得分:2)
你应该尝试这样做:
Public Sub UsingDataReader(ByVal connectionString As String, ByVal commandText As String, ByVal action As Action(Of SQLite.SQLiteDataReader))
Using connection As New SQLite.SQLiteConnection(connectionString)
Using command As New SQLite.SQLiteCommand(commandText, connection)
Using reader = command.ExecuteReader()
action(reader)
End Using
End Using
End Using
End Sub
然后你可以这样调用代码:
UsingDataReader("/* your connection string here */", "SELECT * FROM settings", _
Sub (r)
Do While r.Read
'do something
Loop
End Sub)
这确保在Sub
完成后关闭所有一次性引用。
答案 1 :(得分:1)
第一个问题是并非所有一次性用品都被处理掉了。我们确信传递给该帮助程序的连接位于Using
块中,但该命令也需要处理,因为它具有对连接的引用:
Dim cmd As New SQLiteCommand(sql, dbcon)
即使您不使用重载的构造函数,为了工作,您也可以在某处设置连接属性。这说明了这种"数据库助手的问题之一。方法:DBConnection
,DBCommand
和DBReader
对象非常紧密地协同工作,但它们是使用不同范围的不同方法创建的,您通常无法查看是否所有内容都已清除正确的。
发布的代码将始终失败,因为DBCommand
对象 - 以及扩展名DBConnection
- 未被处理。但即使你正确清理,汇集也会使DBConnection
保持活跃一段时间jmcilhinney explains。以下是2个修复:
Using dbcon As New SQLiteConnection(LiteConnStr),
cmd As New SQLiteCommand(sql, dbcon)
dbcon.Open()
Dim n As Int32 = 0
Using rdr = cmd.ExecuteReader
While rdr.Read
' == DoSomething()
Console.WriteLine("{0} == {1}", n, rdr.GetString(0))
n += 1
End While
End Using
' Clears the connection pool associated with the connection.
' Any other active connections using the same database file will be
' discarded instead of returned to the pool when they are closed.
SQLiteConnection.ClearPool(dbcon)
End Using
File.Delete(sqlFile)
dbCon
和cmd
个对象是"堆叠"在一个Using
语句中减少缩进。
这将关闭并放弃池中的任何和所有连接,提供它们是Disposed
- 以及引用它们的任何对象。如果您使用Dim cmd ...
,则需要明确处理它。
我认为这更加火腿,但它包含在内以便完整。
Using dbcon As New SQLiteConnection(LiteConnStr),
cmd As New SQLiteCommand(sql, dbcon)
...
Using rdr = cmd.ExecuteReader
...
End Using
End Using
GC.WaitForPendingFinalizers()
File.Delete(sqlFile)
只要一切都妥善处理,这也有效。除非绝对必要,否则我不想乱用GC。这里的问题是清理不仅限于DBProvider对象,而是任何已经处理并正在等待GC的东西。
然而第三种解决方法是关闭池,但你仍然需要处理所有内容。
答案 2 :(得分:0)
您还需要关闭与数据库的cnUser
连接。
关闭/丢弃阅读器不一定关闭/处置打开的连接。