¿Cómo deshace TransactionScope las transacciones?

99

Estoy escribiendo una prueba de integración en la que insertaré varios objetos en una base de datos y luego verificaré si mi método recupera esos objetos.

Mi conexión a la base de datos es a través de NHibernate ... y mi método habitual para crear una prueba de este tipo sería hacer lo siguiente:

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

Sin embargo, recientemente descubrí TransactionScope, que aparentemente se puede usar para este mismo propósito ...

Un código de ejemplo que encontré es el siguiente:

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;

}

Creo que si no incluyo la línea, txScope.Complete()los datos insertados se revertirán. Pero, por desgracia no entiendo cómo es posible ... ¿cómo el txScopeobjeto mantener un seguimiento de la deptAdaptery empAdapterlos objetos y sus transacciones en la base de datos.

Siento que me falta un poco de información aquí ... ¿realmente puedo reemplazar mis llamadas BeginTransaction()y RollbackTransaction() rodeando mi código usando TransactionScope?

Si no es así, ¿cómo funciona entonces TransactionScoperevertir las transacciones?

mezoide
fuente
Nunca he usado NHibernate, pero tal vez este enlace te ayude.
Si está buscando una mejor manera de administrar sus sesiones de NHibernate para agrupar las operaciones en transacciones, es posible que desee consultar mi publicación de blog sobre ese tema dotnetchris.wordpress.com/2009/01/27/…
Chris Marisic

Respuestas:

107

Básicamente, TransactionScope no rastrea su Adaptador, lo que hace es rastrear las conexiones de la base de datos. Cuando abre una conexión de base de datos, las conexiones verán si hay una transacción ambiental (alcance de transacción) y, si es así, se alistará en ella. Precaución si hay más de una conexión al mismo servidor SQL, esto escalará a una transacción distribuida.

¿Qué sucede ya que está usando un bloque de uso? Se asegura de que se llamará a dispose incluso si ocurre una excepción. Entonces, si se llama a dispose antes de txScope.Complete (), TransactionScope le dirá a las conexiones que deshagan sus transacciones (o el DTC).

JoshBerke
fuente
10
TransactionScope no rastrea nada más que la Transacción actual en el hilo y la modifica si es necesario según el modelo (requiere, requiere nuevo, etc., etc.). La transacción simplemente notifica todo lo que se inscribe en ella, no solo las conexiones a la base de datos.
casperOne
1
Creo que esto no es del todo cierto. Hice un rastreo parcial del código fuente de TransactionScope y también vi este msdn.microsoft.com/en-us/library/ms172152(v=vs.90).aspx que dice "Si no creó la transacción, la confirmación se produce siempre que el propietario del objeto CommittableTransaction llama a Commit. En ese momento, el administrador de transacciones llama a los administradores de recursos y les informa que se comprometan o deshagan, en función de si se llamó al método Complete en el objeto TransactionScope ". El seguimiento de origen también indica este comportamiento.
user44298
Encontré esta SO Q&A útil: IEnlistmentNotification
mungflesh
Aún no me queda claro. Parece que los objetos con métodos llamados dentro del alcance de la transacción deben cooperar con el mecanismo de transacción. Deben buscar notificaciones de confirmación / reversión por parte del sistema y poder retroceder ellos mismos, ya que son ellos los que realizan la reversión cuando sea necesario (si se ejecutó una eliminación de archivo, obviamente no podemos retroceder mágicamente a menos que tomemos alguna medida de precaución). También parece que las operaciones del servidor SQL son cooperativas. Pero, ¿hay algún otro objeto cooperativo en .Net? ¿Y cómo escribir una clase que sea cooperativa? ¿Documentación?
minutos
54

La TransactionScopeclase trabaja con la Transactionclase , que es específica del hilo.

Cuando TransactionScopese crea, comprueba si hay un Transactionpara el hilo; si existe, lo usa; de lo contrario, crea uno nuevo y lo coloca en la pila.

Si usa uno existente, simplemente incrementa un contador para lanzamientos (ya que tiene que llamarlo Dispose). En el último lanzamiento, si Transactionno se comprometió, revierte todo el trabajo.

En cuanto a por qué las clases parecen saber mágicamente sobre transacciones, eso se deja como un detalle de implementación para aquellas clases que deseen trabajar con este modelo.

Cuando crea sus instancias deptAdaptery emptAdapter, comprueban si hay una transacción actual en el hilo (la Currentpropiedad estática de la Transactionclase). Si lo hay, entonces se registra a sí mismo con el Transaction, para participar en la secuencia de confirmación / retroceso (que Transactioncontrola y podría propagarse a diferentes coordinadores de transacciones, como kernel, distribuidos, etc.).

casperOne
fuente
4
¿Cómo funciona con SqlConnection (s) creadas dentro del alcance? ¿La clase SqlConnection utiliza internamente la clase Transaction que a su vez se alista en TransactionScope? ¿O se alista directamente en el TLS?
Kakira