如何使SqlDataReader线程安全/转换为线程安全类型

时间:2016-11-10 17:10:59

标签: vb.net refactoring task-parallel-library

我正在处理用VB.Net编写的遗留应用程序。我的任务是使用Paralel任务库并线程化应用程序。大部分"工作"是一个以SqlDataReader对象为中心的while循环。为了开发人员的功劳,它被分解为逻辑方法和一个真正的工作方法。主要问题是处理各个任务的所有方法都接受SqlDataReader作为参数。我知道SqlDataReader并不是真正的线程安全,并且它的使用方式根本不是线程安全的。我想要做的是将SqlDataReader转换为ConcurrentQueue或IEnumerable,然后让#34; work"线程并处理该集合中的数据:

Using Command As New SqlCommand(StoredProcedure, Connection)
Command.CommandType = CommandType.StoredProcedure
Command.CommandTimeout = 0
Command.Parameters.Add("@Carrier", SqlDbType.VarChar, 50).Value = sCarrier
Using Reader As SqlDataReader = Command.ExecuteReader
    If Reader.HasRows = True Then
        SetReaderOrdinals(Reader)
        Adjustments = New StringBuilder


        'TODO this appears to be the bulk of the work in the application
        While Reader.Read
            Adjustments.Clear()
            CommitCount += 1
            If Reader.IsDBNull(SomeValue) = False Then
                Select Case stuff
                    Case 1
                        DoThingForOne(Reader)
                    Case 2
                        DoThingForTwo(Reader)
                    Case 3
                        DoThingForThree(Reader)
                    Case 4
                        DoThingForFour(Reader)
                    Case 5
                        DoThingForFive(Reader)
                    Case 6
                        DoThingForSix(Reader)
                    Case Else
                        'Log something
                        Exit While
                End Select
            Else
                'We Failed
            End If
        End While

在这些方法中,rdr在ex:

的那些方法中起作用
If Rdr.GetString(SomeValue).Trim.Length >= 5 Then

If Rrd.IsDBNull(SomeValue)

Rrd.GetInt32(SomeValue)

我想做的是:

'I know this isn't how you convert it but I am not sure how you do
Dim rows AS IEnumerable(of MyObject) = Reader

'Create threads and spawn them here

'act upon the collection here in many threads
Parallel.For Each row in rows
    'Do row stuff here 
    If row Not Nothing Then 
                Select Case stuff
                    Case 1
                        DoThingForOne(row)
                    Case 2
                        DoThingForTwo(row)
                    Case 3
                        DoThingForThree(row)
                    Case 4
                        DoThingForFour(row)
                    Case 5
                        DoThingForFive(row)
                    Case 6
                        DoThingForSix(row)
                    Case Else
                        'Log something
                        Exit For
                End Select
            Else
                'We Failed
            End If
        End For

我不确定这是否合理或是解决这个问题的最佳方法,但这是我想到的第一件事。

任何建议?

1 个答案:

答案 0 :(得分:2)

如果您将数据库读取器代码放入迭代器函数中,那么将为您提供将其转换为IEnumerable的方法,例如

Iterator Function ReadMyObjects() As IEnumerable(Of MyObject)
    Using cn = New SqlConnection("...")
        cn.Open()
        Using cmd = New SqlCommand("...", cn)
            Using rdr = cmd.ExecuteReader()
                If rdr.HasRows Then
                    While rdr.Read()
                        Yield New MyObject() With {
                            .PropA = rdr.GetString(rdr.GetOrdinal("A"))
                        }
                    End While
                End If
            End Using
        End Using
    End Using
End Function

然后您可以在并行循环中使用它:

Parallel.ForEach(
    ReadMyObjects(),
    Sub(item As MyObject)
        ' do something with item
    End Sub
)