分散トランザクションでの複数のデータベース接続の動作を判断しようとしています。
一連のスレッドを生成する長時間実行プロセスがあり、各スレッドはそのDB接続などの管理を担当します。これらはすべてトランザクションスコープ内で実行され、各スレッドはオブジェクトを介してトランザクションに参加しDependentTransaction
ます。
このプロセスを並行して実行しようとすると、いくつかの問題が発生しました。つまり、トランザクションでクエリを同時に実行できないようなブロックがあるようです。
私が知りたいのは、トランザクションコーディネーターが同じDBへの複数の接続からのクエリをどのように処理するか、そしてスレッド間で接続オブジェクトを渡すことが推奨されるかどうかです。
MS SQLではトランザクションごとに1つの接続しか許可されていないことを読みましたが、同じトランザクションで同じDBへの複数の接続を作成して初期化できることは明らかです。接続を開くときに「別のセッションで使用されているトランザクションコンテキスト」例外が発生しない限り、スレッドを並列に実行することはできません。その結果、接続は同時に実行されるのではなく実行を待機する必要があり、最終的にコードは完了まで実行されますが、このロックの問題のためにアプリをスレッド化することによる純利益はありません。
コードは次のようになります。
Sub StartThreads()
Using Scope As New TransactionScope
Dim TL(100) As Tasks.Task
Dim dTx As DependentTransaction
For i As Int32 = 0 To 100
Dim A(1) As Object
dTx = CType(Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete), DependentTransaction)
'A(0) = some_other_data
A(1) = dTx 'the Dependent Transaction
TL(i) = Tasks.Task.Factory.StartNew(AddressOf Me.ProcessData, A) 'Start the thread and add it to the array
Next
Tasks.Task.WaitAll(TL) 'Wait for threads to finish
Scope.Complete()
End Using
End Sub
Dim TransLock As New Object
Sub ProcessData(ByVal A As Object)
Dim DTX As DependentTransaction = A(1)
Dim Trans As Transactions.TransactionScope
Dim I As Int32
Do While True
Try
SyncLock (TransLock)
Trans = New Transactions.TransactionScope(DTX, TimeSpan.FromMinutes(1))
End SyncLock
Exit Do
Catch ex As TransactionAbortedException
If ex.ToString.Contains("Failure while attempting to promote transaction") Then
ElseIf ex.Message = "The transaction has aborted." Then
Throw New Exception(ex.ToString)
Exit Sub
End If
I += 1
If I > 5 Then
Throw New Exception(ex.ToString)
End If
Catch ex As Exception
End Try
Thread.Sleep(10)
Loop
Using Trans
Using DALS As New DAC.DALScope
Do While True
Try
SyncLock (TransLock)
'This opens two connection to the same DB for later use.
DALS.CurrentDAL.OpenConnection(DAC.DAL.ConnectionList.FirstConnection)
DALS.CurrentDAL.OpenConnection(DAC.DAL.ConnectionList.SecondConnection)
End SyncLock
Exit Do
Catch ex As Exception
'This is usually where I find the bottleneck
'"Transaction context in use by another session" is the exception that I get
Thread.Sleep(100)
End Try
Loop
'*****************
'Do some work here
'*****************
Trans.Complete()
End Using
End Using
DTX.Complete()
End Sub
編集
私のテストは、これができないことを決定的に示しました。複数の接続がある場合、または同じ接続が使用されている場合でも、トランザクション内のすべての要求または質問は順番に処理されます。
おそらく、彼らは将来この振る舞いを変えるでしょう。