Работает ли TransactionScope с уже существующими соединениями? - PullRequest
6 голосов
/ 13 февраля 2012

У меня есть такой код:

try
{
    using (TransactionScope scope = new TransactionScope())
    {
        some_db_function();

        for (i = 0; i < 10; i++)
        {
            some_other_db_function();
        }

        scope.Complete();
    }
}
catch (Exception ex)
{
   MessageBox.Show(ex.Message + " all done transactions will rollback");   
}

и внутри функций БД происходит нечто подобное:

private void some_db_functions()
{
    using (TransactionScope scope = new TransactionScope())
    {
       //some processing on db
       scope.Complete();
    }
}

Предполагается, что в случае каких-либо проблем в транзакциях базы данных, таких как ошибка вставки или обновления в функциях; все транзакции, которые были сделаны до сих пор, откатываются. Но это не работает так; и хотя он генерирует исключение и scope.Complete() в родительской функции никогда не срабатывает, все равно ничего не откатывается.

Где проблема?

Ответы [ 2 ]

14 голосов
/ 13 февраля 2012

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

Неявное зачисление соединений не поддерживается. Записаться в Объем транзакции, вы можете сделать следующее:

Открытие соединения в области транзакции.

Или, если соединение уже открыто, вызовите метод EnlistTransaction на объекте соединения.

1012 * Ref *.

Это подключит существующее соединение:

connection.EnlistTransaction(Transaction.Current)
12 голосов
/ 13 февраля 2012

IIRC, автоматическое зачисление в окружающие транзакции происходит при создании / открытии соединения;если вы создаете соединение в рамках транзакции, все должно быть хорошо.Однако:

все они используют одно и то же соединение, объявленное ранее

, если соединение существует вне транзакции, оно не будет подключено.

Лучше всего создавать / открывать соединение только вокруг единицы работы, а не навсегда (и: пусть пул соединений выполняет свою работу).Если вы следуете этой практике, она должна работать нормально.Итак:

Это не будет работать:

using(var conn = CreateAndOpenConnection()) {
    // ...
    using(var tran = new TransactionScope()) {
        SomeOperations(conn);
        tran.Complete();
    }
    // ...
}

где-как это должно работать:

using(var tran = new TransactionScope()) {
    // ...
    using(var conn = CreateAndOpenConnection()) {
        SomeOperations(conn);
    }
    tran.Complete();
    // ...
}
...