Wie verhalten sich verteilte Transaktionen mit mehreren Verbindungen zur gleichen Datenbank in einer Thread-Umgebung?
Ich versuche, das Verhalten mehrerer Datenbankverbindungen in einer verteilten Transaktion zu ermitteln.
Ich habe einen lang laufenden Prozess, der eine Reihe von Threads erzeugt, und jeder Thread ist dann für die Verwaltung seiner DB-Verbindungen und dergleichen verantwortlich. All dies läuft innerhalb des Transaktionsbereichs und jeder Thread wird über a in die Transaktion eingetragenDependentTransaction
Objekt.
Als ich diesen Prozess parallel startete, stieß ich auf einige Probleme, nämlich dass es anscheinend eine Art Block gab, der die gleichzeitige Ausführung der Abfragen für die Transaktion verhinderte.
Ich möchte wissen, wie der Transaktionskoordinator Abfragen von mehreren Verbindungen zur gleichen Datenbank verarbeitet und ob es überhaupt ratsam ist, ein Verbindungsobjekt über Threads zu übergeben.
Ich habe gelesen, dass MS SQL nur eine Verbindung pro Transaktion zulässt, aber ich bin eindeutig in der Lage, mehr als eine Verbindung zu derselben Datenbank in derselben Transaktion zu erstellen und zu initialisieren. Ich kann die Threads einfach nicht parallel ausführen, ohne beim Öffnen der Verbindungen die Ausnahme "Transaktionskontext wird von einer anderen Sitzung verwendet" zu erhalten. Dies hat zur Folge, dass die Verbindungen warten müssen, bis sie ausgeführt werden, anstatt gleichzeitig ausgeführt zu werden. Am Ende wird der Code vollständig ausgeführt, aber aufgrund dieses Sperrproblems kann das Threading der App nicht fortgesetzt werden.
Der Code sieht ungefähr so aus.
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
BEARBEITEN
Meine Tests haben eindeutig gezeigt, dass dies nicht möglich ist. Auch wenn es mehr als eine Verbindung gibt oder dieselbe Verbindung verwendet wird, werden alle Anforderungen in der Transaktion oder die Fragen nacheinander verarbeitet.
Vielleicht werden sie dieses Verhalten in Zukunft ändern.