Как TransactionScope откатывает транзакции?

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

Мое подключение к базе данных осуществляется через 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 для отката транзакций?

Ответ 1

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

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

Ответ 2

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

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

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

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

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