Откат вложенного / дочернего TransactionScope - PullRequest
26 голосов
/ 30 апреля 2010

Я пытаюсь вложить TransactionScopes (.net 4.0) так же, как вы вкладываете транзакции в SQL Server, однако похоже, что они работают по-другому. Я хочу, чтобы мои дочерние транзакции могли откатываться, если они терпят неудачу, но позволяю родительской транзакции решать, следует ли зафиксировать / откатить всю операцию. Проблема в том, что когда происходит первое завершение, транзакция откатывается. Я понимаю, что завершить это совсем не так.

Очень упрощенный пример того, что я пытаюсь сделать:

static void Main(string[] args)
{
    using(var scope = new TransactionScope()) // Trn A
    {
        // Insert Data A

        DoWork(true);
        DoWork(false);

        // Rollback or Commit
    }
}

// This class is a few layers down
static void DoWork(bool fail)
{
    using(var scope = new TransactionScope()) // Trn B
    {
        // Update Data A

        if(!fail)
        {
            scope.Complete();
        }
    }
}

Я не могу использовать параметры «Подавить» или «Требовать нового», поскольку Trn B использует данные, введенные Trn A. Если я использую эти параметры, Trn B блокируется Trn A.

Есть идеи, как заставить его работать или, если это возможно, использовать пространство имен System.Transactions?

Спасибо

1 Ответ

47 голосов
/ 30 апреля 2010

Вам, вероятно, не понравится этот ответ, но ...

Голосование во вложенном объеме

Хотя вложенная область может присоединиться к внешней транзакции корневой области, вызов Complete во вложенной области не влияет на корневую область. Только если все области от корневой области до последней вложенной области проголосуют за принятие транзакции, транзакция будет зафиксирована.

Реализация неявной транзакции с использованием области транзакции )

Класс TransactionScope, к сожалению, не предоставляет какого-либо механизма (о котором я знаю) для разделения единиц работы. Это все или ничего. Вы можете предотвратить выполнение любой транзакции на определенной единице работы, используя TransactionScopeOption.Suppress, но это, вероятно, не то, что вам нужно, поскольку тогда вы потеряете атомарность для всего, что находится внутри этой области.

При использовании TransactionScope существует только одна «окружающая» транзакция. Как только TransactionScope удаляется или собирается без выполнения Complete, вся окружающая транзакция откатывается; все, игра окончена.

На самом деле, SQL Server вообще не поддерживает истинные вложенные транзакции, хотя возможно (хотя и несколько не интуитивно понятно) достичь того же конечного результата с соответствующим использованием операторов SAVE TRAN. Реализация этой логики как хранимой процедуры (или нескольких из них) может быть вашим лучшим вариантом, если вам требуется именно это поведение.

...