In che modo TransactionScope ripristina le transazioni?


99

Sto scrivendo un test di integrazione in cui inserirò un numero di oggetti in un database e quindi verificherò se il mio metodo recupera quegli oggetti.

La mia connessione al database avviene tramite NHibernate ... e il mio metodo abituale per creare un test di questo tipo sarebbe di fare quanto segue:

NHibernateSession.BeginTransaction();

//use nhibernate to insert objects into database
//retrieve objects via my method
//verify actual objects returned are the same as those inserted

NHibernateSession.RollbackTransaction();

Tuttavia, di recente ho scoperto TransactionScope che apparentemente può essere utilizzato proprio per questo scopo ...

Alcuni esempi di codice che ho trovato sono i seguenti:

public static int AddDepartmentWithEmployees(Department dept)
{

    int res = 0;

    DepartmentAdapter deptAdapter = new DepartmentAdapter();
    EmployeeAdapter empAdapter = new EmployeeAdapter();
    using (TransactionScope txScope = new TransactionScope())
    {

        res += deptAdapter.Insert(dept.DepartmentName);
        //Custom method made to return Department ID 
        //after inserting the department "Identity Column"
        dept.DepartmentID = deptAdapter.GetInsertReturnValue();
        foreach(Employee emp in dept.Employees)
        {

            emp.EmployeeDeptID = dept.DepartmentID;
            res += empAdapter.Insert(emp.EmployeeName, emp.EmployeeDeptID);

        }
        txScope.Complete();

    }
    return res;

}

Credo che se non includo la riga, txScope.Complete()i dati inseriti verranno annullati. Ma purtroppo non capisco come ciò sia possibile ... come fa l' txScopeoggetto di tenere una traccia delle deptAdaptere empAdapteroggetti e le loro transazioni sul database.

Mi sento come se mi mancassero un po 'di informazioni qui ... sono davvero in grado di sostituire le mie chiamate BeginTransaction()and RollbackTransaction() circondando il mio codice usando TransactionScope?

In caso contrario, come TransactionScopefunziona il rollback delle transazioni?


Non ho mai usato NHibernate, ma forse questo link ti aiuterà.

Se stai cercando un modo migliore per gestire le tue sessioni NHibernate per raggruppare le operazioni in transazioni, potresti voler controllare il mio post sul blog su questo argomento dotnetchris.wordpress.com/2009/01/27/…
Chris Marisic

Risposte:


107

In sostanza TransactionScope non tiene traccia dell'adattatore, quello che fa è tenere traccia delle connessioni al database. Quando apri una connessione DB, le connessioni controlleranno se è presente una transazione ambientale (Transaction Scope) e in tal caso si arruoleranno con essa. Attenzione, se ci sono più connessioni allo stesso server SQL, questo passerà a una transazione distribuita.

Cosa succede poiché stai usando un blocco using, stai assicurando che dispose verrà chiamato anche se si verifica un'eccezione. Quindi, se dispose viene chiamato prima di txScope.Complete (), TransactionScope dirà alle connessioni di eseguire il rollback delle loro transazioni (o del DTC).


10
TransactionScope non tiene traccia di nient'altro che la Transazione corrente sul thread e la modifica se necessario in base al modello (richiede, richiede nuovo, ecc. Ecc.). La transazione notifica semplicemente tutto ciò che si arruola con essa, non solo le connessioni al database.
casperOne

1
Penso che questo non sia del tutto vero. Ho fatto una traccia parziale del codice sorgente di TransactionScope e ho anche visto questo msdn.microsoft.com/en-us/library/ms172152(v=vs.90).aspx che dice "Se non ha creato la transazione, il commit si verifica ogni volta che Commit viene chiamato dal proprietario dell'oggetto CommittableTransaction. A quel punto il gestore delle transazioni chiama i gestori delle risorse e li informa di eseguire il commit o il rollback, a seconda che il metodo Complete sia stato chiamato sull'oggetto TransactionScope. " La traccia di origine indica anche questo comportamento.
user44298

Ho trovato utile questa domanda
risposta

Ancora poco chiaro per me. Sembra che gli oggetti con metodi chiamati all'interno dell'ambito della transazione debbano essere cooperativi con il meccanismo di transazione. Devono cercare le notifiche di commit / rollback dal sistema ed essere in grado di eseguire il rollback da soli poiché sono loro a eseguire il rollback quando richiesto (se è stata eseguita una cancellazione di file, ovviamente non possiamo ripristinarla magicamente a meno che non abbiamo preso alcune misure precauzionali). Sembra anche che le operazioni del server SQL siano cooperative. Ma ci sono altri oggetti cooperativi in ​​.Net? E come scrivere una classe che sia cooperativa? Documentazione?
min.

54

La TransactionScopeclasse funziona con la Transactionclasse , che è specifica del thread.

Quando TransactionScopeviene creato, controlla se esiste un Transactionper il thread; se ne esiste uno lo usa, altrimenti ne crea uno nuovo e lo mette in pila.

Se ne utilizza uno esistente, incrementa semplicemente un contatore per i rilasci (dal momento che devi chiamarlo Dispose). Nell'ultima versione, se Transactionnon è stato commesso, ripristina tutto il lavoro.

Per quanto riguarda il motivo per cui le classi sembrano conoscere magicamente le transazioni, questo viene lasciato come dettaglio di implementazione per quelle classi che desiderano lavorare con questo modello.

Quando crei le tue istanze deptAdaptere emptAdapter, controllano per vedere se c'è una transazione corrente sul thread (la Currentproprietà statica sulla Transactionclasse). Se c'è, allora si registra con il Transaction, per prendere parte alla sequenza di commit / rollback (che Transactioncontrolla e potrebbe propagarsi a diversi coordinatori di transazione, come kernel, distribuito, ecc.).


4
Come funziona con SqlConnection creati nell'ambito? La classe SqlConnection utilizza internamente la classe Transaction che a sua volta si arruola con TransactionScope? O si arruola direttamente nel TLS?
Kakira
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.