同时OleDbDataAdapter.Fill调用单独的线程?

时间:2014-04-24 20:19:31

标签: vb.net multithreading oledbdataadapter

这里的第一个计时器,所以对我来说很容易。理论上可以同时在不同的线程上执行两个OleDBDataAdapter.Fill调用 - 或者这是否存在根本缺陷?

考虑一个包含2个按钮和2个datagridviews的表单。每个按钮单击使用Async \ Await \ Task.Run模式启动工作线程,该模式调用方法以返回填充的数据表并将其分配给其中一个datagridviews。第一个线程中的.Fill需要30秒才能完成。第二个线程中的.Fill需要1秒才能完成。单独启动时,两个按钮都按预期工作。

但是,如果我启动第一个工作线程(30秒到Fill),然后启动第二个线程(1秒Fill),则第一个.Fill调用完成之前不会填充第二个DataGridView。我希望第二个datagridview在1秒内填充,第一个datagridview在~30秒后填充。

我在示例代码中使用OleDBDataAdapter和SqlDataAdapter复制了此问题。如果我用一个简单的Thread.Sleep(30000)替换长时间运行的查询,则会立即填充第二个datagridview。这让我相信这不是我的设计模式的问题,而是同时发出.Fill调用的特定内容。

Private Async Sub UltraButton1_Click(sender As Object, e As EventArgs) Handles UltraButton1.Click

    Dim Args As New GetDataArguments
    Args.ConnectionString = "some connection string"
    Args.Query = "SELECT LongRunningQuery from Table"

    Dim DT As DataTable = Await Task.Run(Function() FillDataTable(Args))
    If DataGridView1.DataSource Is Nothing Then
        DataGridView1.DataSource = DT
    Else
        CType(DataGridView1.DataSource, DataTable).Merge(DT)
    End If

End Sub

Function FillDataTable(Args As GetDataArguments) As DataTable

    Dim DS As New DataTable

    Using Connection As New OleDbConnection(Args.ConnectionString)
        Using DBCommand As New OleDbCommand(Args.Query, Connection)
            Using DataAdapter As New OleDbDataAdapter(DBCommand)
                DataAdapter.Fill(DS)
            End Using
        End Using
    End Using

    Return DS

End Function

Private Async Sub UltraButton2_Click(sender As Object, e As EventArgs) Handles UltraButton2.Click

    Dim DS As DataTable = Await Task.Run(Function() LoadSecondDGV("1234"))
    DataGridView2.DataSource = DS

End Sub

Function LoadSecondDGV(pnum As String) As DataTable

    Dim DX As New DataTable

    Using xConn As New OleDbConnection("some connection string")
        Using DataAdapter As New OleDbDataAdapter("Select name from products where PNUM = """ & pnum & """", xConn)
            DataAdapter.Fill(DX)
        End Using
    End Using

    Return DX

End Function

1 个答案:

答案 0 :(得分:0)

这取决于数据源是什么。某些数据源(如Excel)一次只允许一个连接。其他数据源(如Access)将允许多个连接,但实际上是连续完成结果,这样您就无法获得任何收益。其他数据源(如Sql Server)将允许您正在寻找的真正并行活动。

在这种情况下,您提到您还尝试使用SqlDataAdapter,它向我表明您正在与Sql Server通信,这应该是可能的。这可能是你的第一个查询是锁定第二个查询所需的一些数据。您可以通过更改transaction isolation level或仔细使用with (nolock)提示(前一选项是强烈首选)来解决此问题。

要记住的另一件事是,只有在您为每个查询使用单独的连接时,或者如果您专门启用了多个活动结果集功能,这才能起作用。看起来你在这里使用了单独的连接对象,所以你应该没事,但它仍然是我认为值得提出的东西。

最后,我需要评论您的FillDataTable()方法。此方法要求您提供已完成的Sql字符串,这实际上会强制您编写将极易受到SQL注入攻击的代码。继续使用如图所示的方法实际上可以保证您的应用程序可能会被提前攻击,而不是更早。您需要修改此方法,以便鼓励您使用参数化查询。