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

100

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

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

мезоид
источник
Я никогда не пользовался NHibernate, но, возможно, эта ссылка вам поможет.
Если вы ищете лучший способ управления сеансами NHibernate для группирования операций в транзакции, возможно, вы захотите проверить мое сообщение в блоге по этой теме dotnetchris.wordpress.com/2009/01/27/…
Крис Марисич,

Ответы:

108

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

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

Джош Берке
источник
10
TransactionScope не отслеживает ничего, кроме текущей транзакции в потоке, и при необходимости изменяет ее на основе модели (требуется, требуется новая и т. Д. И т. Д.). Транзакция просто уведомляет все, что с ней связано, а не только соединения с базой данных.
casperOne
1
Думаю, это не совсем так. Я частично отследил исходный код TransactionScope, и я также увидел это msdn.microsoft.com/en-us/library/ms172152(v=vs.90).aspx, в котором говорится: «Если он не создал транзакцию, фиксация происходит всякий раз, когда владелец объекта CommittableTransaction вызывает фиксацию. В этот момент диспетчер транзакций вызывает диспетчеров ресурсов и сообщает им о фиксации или откате в зависимости от того, был ли вызван метод Complete для объекта TransactionScope ». Трассировка источника также указывает на это поведение.
user44298 04
Я нашел этот SO Q&A полезным: IEnlistmentNotification
mungflesh
Мне все еще непонятно. Кажется, что объекты с методами, вызываемыми в рамках транзакции, должны взаимодействовать с механизмом транзакции. Они должны искать уведомления о фиксации / откате системой и иметь возможность откатиться, поскольку именно они выполняют откат, когда это необходимо (если было выполнено удаление файла, очевидно, мы не можем волшебным образом откатить его, если не какая-то мера предосторожности). Также кажется, что операции SQL-сервера согласованы. Но есть ли в .Net какой-либо другой кооперативный объект? А как написать кооперативный класс? Документация?
мин
54

TransactionScopeКласс работает с Transactionклассом , который является поточно-специфичны.

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

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

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

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

casperOne
источник
4
Как это работает с SqlConnection (s), созданным в области видимости? Использует ли класс SqlConnection внутри класс Transaction, который, в свою очередь, подключается к TransactionScope? Или он напрямую подключается к TLS?
Kakira 08