vb.net - 一次性类引用

标签 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”而发生锁定。

有人看到我做错了什么/什么使数据库锁定了吗?

我认为在数据读取器的“最终使用”之后,还将处理SQLiteCommand,因此没有对数据库的进一步引用。

最佳答案

第一个问题是并非所有一次性用品都被丢弃。我们确信传递给该帮助程序的连接位于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的对象。
第三种解决方法是关闭池,但是您仍然必须处置所有内容。

关于vb.net - 一次性类引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45872668/

相关文章:

vb.net - 如何选择绑定(bind)到 DataTable 的 Datagridview 中的可见列

c# - 如何搜索不属于高级搜索结果的 Outlook.MailItems

ios - 在 Info.plist CFBundleSupportedPlatforms 或 Mach-O LC_VERSION_MIN 中找不到平台系列 for sqlite3

SQLite CASE 多条件查询

database - 使用 VB.Net 部署 Access 数据库但未部署数据库

c# - 仅加载特定操作系统版本的样式

mysql - 选择具有最低值的随机数据库记录

android - SQLite 向表中添加一个列表

android - 房间数据库,SELECT * FROM table by a given day

c# - Sqlite3 数据库损坏 - 在 Xamarin 中修复