Есть ли способ проверить потенциальную транзакцию зомби, чтобы увидеть, можно ли ее откатить? - PullRequest
4 голосов
/ 23 мая 2009

Если вызов sql завершится неудачно, скажем, из-за тупика из-за тайм-аута, транзакция может превратиться в транзакцию зомби - я предполагаю, что мой код или код платформы выполняет откат. SqlTransaction не является нулевым, но это зомби может выдать ошибку, если вы попытаетесь выполнить откат (). Я не могу найти собственность .IsZombie.

// Make sure the transaction is not null
if (transaction != null)
{
    //TODO: Is there a way to test a transaction to see if it can be rolled back?
    transaction.Rollback();  
}

Ответы [ 4 ]

2 голосов
/ 23 мая 2009

Вы можете попробовать использовать класс TransactionScope из пространства имен .NET 2.0 System.Transactions. Этот класс позволяет указать время ожидания, после которого транзакция будет автоматически отменена и откатана. ADO.NET в .NET 2.0+ поддерживает TransactionScope и автоматически зарегистрирует DbTransaction в области, если он присутствует во время вызова базы данных:

public void DoSomething()
{
    using (TransactionScope scope = new TransactionScope(TransactionScopeOptions.Required, TimeSpan.FromSeconds(60)))
    {
        MyDac();

        scope.Complete(); // If timeout occurrs, this line is never hit, scope is disposed, which causes rollback if Complete() was not called
    }
}

public class MyDac()
{

    using (SqlConnection ...)
    {
        using (SqlCommand ...)
        {
            // Do something with ADO.NET here...it will autoenroll if a transaction scope is present
        }
    }
}

TransactionScope внутренне создает System.Transactions.Transaction, которая по умолчанию разрешает выполнение легких транзакций для SQL Server, если задействован только один сервер. Если в транзакции участвует несколько серверов или администраторов распределенных ресурсов, Транзакция, заключенная в TransactionScope, будет преобразована в распределенную транзакцию, для которой потребуется MSDTC для координации, что может усложнить использование TransactionScope. Если все ваши транзакции легковесны, TransactionScope может предложить множество преимуществ по сравнению с управлением транзакциями БД вручную.

1 голос
/ 01 мая 2018

Старый вопрос, который я знаю, но недавно я имел дело с этой проблемой и создал для себя небольшую вспомогательную функцию для безопасной фиксации / отката SqlTransactions. Я думал, что выложу это на тот случай, если кто-то еще найдет решение этой проблемы.

public void CompleteTransaction(SqlTransaction transaction, bool isRollback) {
    if (transaction == null) { return; }
    try {
        if (isRollback) { 
            transaction.Rollback(); 
        } else { 
            transaction.Commit(); 
        }
    } catch (InvalidOperationException ex) {
        // In my case, I just ignored exceptions due to zombie transactions, 
        // but you could handle it differently depending on your needs
        if (ex.TargetSite == null || ex.TargetSite.ToString() != "Void ZombieCheck()") {
            throw; // Not a zombie transaction, so re-throw the exception
        }
    }
}

Когда я изучал сведения об исключении для исключения из-за транзакции зомби, я заметил, что TargetSite был Void ZombieCheck(), поэтому мое решение предполагает, что если TargetSite не установлен на это, это не ошибка из-за зомби транзакция.

1 голос
/ 21 декабря 2009

Прошу прощения, но не могу не согласиться. Клиентские транзакции - это то, что позволяет иметь элементарную операцию бизнес-процесса. Если вы хотите переместить все транзакции в БД, вы всегда перемещаете в нее бизнес-логику. Это подход, но крайне не рекомендуется, если вы будете использовать в своей программе слегка сложную логику. Имея whiles / for / foreachs, проверки строк и другие тривиальные операции очень тяжело переносить в БД (а иногда даже невозможно). Однако подсказка о взаимоблокировке представляется весьма полезной и обеспечивает дополнительный контроль над клиентским приложением (что, на мой взгляд, является наилучшим способом).

Приветствия

0 голосов
/ 23 мая 2009

Возможно, вы захотите разместить свой код обработки транзакций внутри базы данных, где вы можете проверить на @@ ERROR = 1205, чтобы определить, был ли ваш запрос жертвой тупика, и в этом случае вы можете повторить попытку или выполнить ROLLBACK. Разрешать клиентским приложениям создавать транзакции и управлять ими немного рискованно, и лучше их избегать, если это возможно.

Надеюсь, это поможет,

Bill

...