一次性课程保留参考

时间:2017-08-25 00:16:09

标签: vb.net sqlite

我在我的项目中经常使用简单的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也会被处理掉,因此没有对数据库的进一步引用。

3 个答案:

答案 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)

即使您不使用重载的构造函数,为了工作,您也可以在某处设置连接属性。这说明了这种"数据库助手的问题之一。方法:DBConnectionDBCommandDBReader对象非常紧密地协同工作,但它们是使用不同范围的不同方法创建的,您通常无法查看是否所有内容都已清除正确的。

发布的代码将始终失败,因为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)

dbConcmd个对象是"堆叠"在一个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连接。

关闭/丢弃阅读器不一定关闭/处置打开的连接。