web-dev-qa-db-fra.com

Comment TransactionScope annule-t-il les transactions?

J'écris un test d'intégration dans lequel je vais insérer un certain nombre d'objets dans une base de données, puis vérifier si ma méthode récupère ces objets.

Ma connexion à la base de données se fait via NHibernate ... et ma méthode habituelle pour créer un tel test consiste à effectuer les opérations suivantes:

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();

Cependant, j'ai récemment découvert TransactionScope , qui peut apparemment être utilisé à cette fin ...

Certains exemple de code que j'ai trouvé est le suivant:

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;

}

Je crois que si je n'inclue pas la ligne txScope.Complete(), les données insérées seront restaurées. Mais malheureusement, je ne comprends pas comment cela est possible ... comment l’objet txScope garde-t-il une trace des objets deptAdapter et empAdapter et de leurs transactions dans la base de données?.

J'ai l'impression qu'il me manque un peu d'informations ici ... Suis-je vraiment capable de remplacer mes appels BeginTransaction() et RollbackTransaction() En entourant mon code avec TransactionScope?

Si non, comment alors TransactionScope fonctionne-t-il pour annuler les transactions?

94
mezoid

Essentiellement, TransactionScope ne suit pas votre adaptateur, mais suit les connexions à la base de données. Lorsque vous ouvrez une connexion à une base de données, les connexions recherchent s'il existe une transaction ambiante (Portée de la transaction) et, si tel est le cas, vous y inscrire. Attention, s'il existe plusieurs connexions au même serveur SQL, cela deviendra une transaction distribuée.

Que se passe-t-il depuis que vous utilisez un bloc using, vous vous assurez que dispose sera appelé même si une exception se produit. Donc, si dispose est appelé avant txScope.Complete (), TransactionScope indiquera aux connexions d'annuler leurs transactions (ou le DTC).

104
JoshBerke

Le TransactionScope class fonctionne avec le Transaction class , qui est spécifique au thread.

Lorsque le TransactionScope est créé, il vérifie s'il existe un Transaction pour le thread; s'il en existe un, il l'utilise, sinon il en crée un nouveau et le place dans la pile.

S'il en utilise un existant, il incrémente simplement un compteur de versions (puisqu'il faut appeler Dispose ). Dans la dernière version, si Transaction n'était pas validé, il annule tout le travail.

Quant aux raisons pour lesquelles les classes semblent savoir par magie sur les transactions, cela reste un détail d'implémentation pour les classes qui souhaitent utiliser ce modèle.

Lorsque vous créez vos instances deptAdapter et emptAdapter, ils vérifient s’il existe une transaction en cours sur le thread (propriété static Current) sur la classe Transaction). Si tel est le cas, il s’enregistre lui-même avec le Transaction pour participer à la séquence commit/rollback (que Transaction contrôle et pourrait propager à différents coordinateurs de transaction, tels que kernel, etc.).

52
casperOne