Как TransactionScope откатывает транзакции? - PullRequest
92 голосов
/ 30 января 2009

Я пишу интеграционный тест, в котором я буду вставлять несколько объектов в базу данных, а затем проверять, получает ли мой метод эти объекты.

Мое соединение с базой данных осуществляется через NHibernate ... и мой обычный метод создания такого теста заключается в следующем:

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

Однако недавно я узнал о TransactionScope , который, по-видимому, можно использовать для этой цели ...

Пример кода , который я нашел , выглядит следующим образом:

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;

}

Я считаю, что если я не включу строку txScope.Complete(), то вставленные данные будут откатываться. Но, к сожалению, я не понимаю, как это возможно ... как объект txScope отслеживает объекты deptAdapter и empAdapter и их транзакции в базе данных.

Я чувствую, что мне здесь не хватает информации ... действительно ли я могу заменить свои BeginTransaction() и RollbackTransaction() вызовы, окружив мой код с помощью TransactionScope?

Если нет, то как TransactionScope работает для отката транзакций?

Ответы [ 2 ]

102 голосов
/ 30 января 2009

По сути TransactionScope не отслеживает ваш адаптер, он отслеживает соединения с базой данных. Когда вы открываете соединение с БД, соединения будут проверять, есть ли окружающая транзакция (объем транзакции) и, если это так, подключиться к ней. Осторожно, если есть еще одно соединение с одним и тем же SQL-сервером, это перерастет в Распределенную транзакцию.

Что происходит, так как вы используете блок using, который вы гарантируете, будет вызван dispose, даже если произойдет исключение. Поэтому, если dispose вызывается до txScope.Complete (), TransactionScope сообщит соединениям об откате их транзакций (или DTC).

52 голосов
/ 30 января 2009

Класс TransactionScope работает с классом Transaction , который зависит от потока.

Когда создается TransactionScope, он проверяет, существует ли Transaction для потока; если он существует, он использует его, в противном случае он создает новый и помещает его в стек.

Если он использует существующий, то он просто увеличивает счетчик для выпусков (так как вам нужно вызвать Dispose для него). В последнем выпуске, если Transaction не был завершен, он откатывает всю работу.

Что касается того, почему классы, кажется, волшебным образом знают о транзакциях, то это оставлено как деталь реализации для тех классов, которые хотят работать с этой моделью.

Когда вы создаете экземпляры deptAdapter и emptAdapter, они проверяют, есть ли в потоке текущая транзакция (статическое Current свойство в классе Transaction). Если есть, то он регистрируется с помощью Transaction, чтобы принять участие в последовательности фиксации / отката (которой управляет Transaction, и он может распространяться на различные координаторы транзакций, такие как ядро, распределенные и т. *

...