Данные, выполненные, хотя System.Transactions.TransactionScope.Commit() не вызываются

В каких обстоятельствах код, завернутый в System.Transactions.TransactionScope, все еще выполняется, даже если исключение было выбрано, а внешний вид никогда не совершал commit?

Существует метод верхнего уровня, завернутый в using (var tx = new TransactionScope()), и который вызывает методы, которые также используют TransactionScope тем же способом.

Я использую типизированные наборы данных с соответствующими таблицами. Может быть, команды в адаптере по какой-то причине не зачисляются? Кто-нибудь из вас знает, как можно проверить, заходят ли они в окружающий TransactionScope или нет?

Ответ 1

Ответ оказался потому, что я создал объект TransactionScope после объекта SqlConnection.

Я перешел от этого:

using (new ConnectionScope())
using (var transaction = new TransactionScope())
{
    // Do something that modifies data

    transaction.Complete();
}

:

using (var transaction = new TransactionScope())
using (new ConnectionScope())
{
    // Do something that modifies data

    transaction.Complete();
}

и теперь он работает!

Итак, мораль этой истории - создать < <20 > первый.

Ответ 2

Очевидным сценарием будет то, что явная спецификация новой транзакции (RequiresNew)/null (Suppress), но также существует тайм-аут/развязка, которая может привести к сбоям в пропуске транзакции. См. Этот более ранний пост (исправление - это просто изменение строки подключения) или полная информация.

Ответ 3

Помните, как работает TransactionScope:
Он устанавливает свойство System.Transactions.Transaction.Current в начале использования области действия, а затем возвращает его к предыдущему значению в конце использования области.

Предыдущее значение зависит от того, где объявлена ​​данная область. Он может находиться внутри другой области.


Вы можете изменить код следующим образом:

using (var sqlConnection = new ConnectionScope())
using (var transaction = new TransactionScope())
{
    sqlConnection.EnlistTransaction(System.Transactions.Transaction.Current);
    // Do something that modifies data
    transaction.Complete();
}

Я показываю эту возможность тем, у кого более сложный код, и не может просто изменить код, чтобы сначала открыть соединение с БД.

Ответ 4

В этом примере (С#,.NetFramework 4.7.1) показано, как мы можем сохранить базу данных, даже если код помещен в TransactionScope. Первый insert будет откатан, а второй insert будет вставлен без транзакции.

См. мой пост, где я прошу помощи в том, как это обнаружить.


using (var transactionScope = new TransactionScope())
{
    using (var connection = new SqlConnection("Server=localhost;Database=TestDB;Trusted_Connection=True"))
    {
        connection.Open();

        new SqlCommand($"INSERT INTO TestTable VALUES('This will be rolled back later')", connection).ExecuteNonQuery();

        var someNestedTransaction = connection.BeginTransaction();
        someNestedTransaction.Rollback();

        new SqlCommand($"INSERT INTO TestTable VALUES('This is not in a transaction, and will be committed')", connection).ExecuteNonQuery();
    }

    throw new Exception("Exiting.");

    transactionScope.Complete();
}