Как 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контролирует и может распространяться на различные координаторы транзакций, такие как ядро, распределенные и т. Д.).


4
Как это работает с SqlConnection (s), созданным в области видимости? Использует ли класс SqlConnection внутри класс Transaction, который, в свою очередь, подключается к TransactionScope? Или он напрямую подключается к TLS?
Kakira 08
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.