Данные, выполненные, хотя 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();
}