Sto cercando di determinare il comportamento di più connessioni di database in una transazione distribuita.Come si comportano le transazioni distribuite con più connessioni allo stesso DB in un ambiente con thread?
Ho un lungo processo in esecuzione che genera una serie di thread e ciascun thread è quindi responsabile della gestione delle sue connessioni DB e così via. Tutto questo viene eseguito all'interno dell'ambito della transazione e ogni thread viene inserito nella transazione tramite un oggetto DependentTransaction
.
Quando sono andato a mettere questo processo in parallelo ho incontrato alcuni problemi, vale a dire che sembra esserci una specie di blocco che impedisce l'esecuzione delle query contemporaneamente alla transazione.
Quello che vorrei sapere è come il coordinatore delle transazioni gestisce le query da più connessioni allo stesso DB e se è addirittura consigliabile passare un oggetto di connessione tra thread?
Ho letto che MS SQL consente solo una connessione per transazione, ma sono chiaramente in grado di creare e inizializzare più di una connessione allo stesso DB nella stessa transazione. Semplicemente non sono in grado di eseguire i thread in parallelo senza ottenere un'eccezione "Contesto transazioni in uso da un'altra sessione" quando si aprono le connessioni. Il risultato è che le connessioni devono attendere per essere eseguite anziché funzionare allo stesso tempo e alla fine il codice viene eseguito fino al completamento, ma non vi è alcun guadagno netto nel threading dell'app a causa di questo problema di blocco.
Il codice è simile a questo.
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
EDIT
miei test hanno definitivamente dimostrato che questo proprio non si può fare. Anche se c'è più di una connessione o la stessa connessione viene utilizzata tutte le richieste nella transazione o le domande vengono elaborate in sequenza.
Forse cambieranno questo comportamento in futuro.
OK Vedo che avete un dilemma. Ma dal punto di vista di SQL una transazione deve avere limiti. Onorare una transazione attraverso più connessioni nella mia mente viola il concetto. Posso chiedere la mia insalata con la mia cena, ma non voglio che il tavolo accanto dica che vogliono la loro insalata con la mia. – Paparazzi