Msgstr "Эта транзакция SqlTransaction завершена; она больше не может использоваться." ... ошибка конфигурации? - PullRequest
45 голосов
/ 15 июня 2011

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

У нас есть приложение .NET для отслеживания наших ресурсов. Существует функция экспорта для копирования ресурса в систему отслеживания времени и систему выставления счетов; это позволяет получить доступ к хранимой процедуре, которая ссылается на базы данных времени и выставления счетов.

Недавно я переместил базу данных биллинговой системы на новый сервер (исходный сервер: Server 2003 SP2, SQL 2005; новый сервер: Server 2008 R2, SQL 2008 R2). У меня есть связанный сервер, который указывает на базы данных 2008 года. Я обновил хранимую процедуру, указав на сервер 2008, а затем получил ошибку о MSDTC и RPC (http://www.safnet.com/writing/tech/archives/2007/06/server_myserver.html). Я включил «rpc / rpc out» на связанном сервере и настроил MSDTC для разрешения доступа к сети (что-то вроде этого: http://www.sqlwebpedia.com/content/msdtc-troubleshooting).

Теперь я получаю вышеприведенное, когда пытаюсь запустить функцию экспорта: «Эта SqlTransaction завершена; она больше не может использоваться». Мне кажется странным, что когда я просто запускаю хранимую процедуру (из SSMS), она говорит, что она успешно завершена.

Кто-нибудь видел это раньше? Я что-то пропустил в конфигурации? Я продолжаю просматривать одни и те же страницы, и единственное, что я обнаружил, это то, что я не перезагружался после внесения изменений в MSDTC (упомянуто здесь: http://social.msdn.microsoft.com/forums/en-US/adodotnetdataproviders/thread/7172223f-acbe-4472-8cdf-feec80fd2e64/).

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

Ответы [ 8 ]

41 голосов
/ 15 июня 2011

Я полагаю, что это сообщение об ошибке связано с "транзакцией зомби".

Поиск возможных областей, где транзакция совершается дважды (или откатывается дважды, или откатывается и фиксируется и т. Д.).Код .Net фиксирует транзакцию после того, как SP уже зафиксировал ее?Код .Net откатывает его при обнаружении ошибки, а затем пытается откатить его снова в предложении catch (или, наконец,)?

Возможно, на старом сервере никогда не возникало условие ошибки, итаким образом, ошибочный код «двойного отката» никогда не срабатывал.Может быть, теперь у вас есть ситуация, когда - это какая-то ошибка конфигурации на новом сервере, и теперь неисправный код получает удар при обработке исключений.

Можете ли вы отладить код ошибки?Есть ли у вас трассировка стека?

6 голосов
/ 13 июля 2014

У меня было это недавно после рефакторинга в новом диспетчере соединений. Новая подпрограмма приняла транзакцию, чтобы ее можно было запустить как часть пакета, проблема была в блоке using:

public IEnumerable<T> Query<T>(IDbTransaction transaction, string command, dynamic param = null)
{
  using (transaction.Connection)
  {
    using (transaction)
    {
      return transaction.Connection.Query<T>(command, new DynamicParameters(param), transaction, commandType: CommandType.StoredProcedure);
    }
  }
}

Похоже, что внешнее использование закрывало базовое соединение, поэтому любые попытки зафиксировать или откатить транзакцию вывели сообщение "This SqlTransaction has completed; it is no longer usable."

Я удалил записи, добавил тест на покрытие, и проблема исчезла.

public IEnumerable<T> Query<T>(IDbTransaction transaction, string command, dynamic param = null)
{
  return transaction.Connection.Query<T>(command, new DynamicParameters(param), transaction, commandType: CommandType.StoredProcedure);
}

Проверьте все, что может закрывать соединение, находясь в контексте транзакции.

4 голосов
/ 21 августа 2015

У меня такая же проблема. Эта ошибка возникает из-за пула соединений. Когда в системе работают два или более пользователей, пул соединений повторно использует соединение и переход. Если первый пользователь выполнит коммит или откат, транзакция не будет использоваться долго.

3 голосов
/ 09 февраля 2015

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

Мой псевдокод был похож на:

var transaction = connection.BeginTransaction();
for(all the lines in a file)
{
     try{
         InsertLineInTable(); // INSERT statement might fail and throw an exception
     }
     catch {
         // notify the user about the error on line x and continue
     }
}

// Commit and Rollback will fail if one of the queries 
// in InsertLineInTable threw an exception
if(CheckTableForErrors())
{
    transaction.Commit();
}
else
{
    transaction.Rollback();
}
3 голосов
/ 15 мая 2013

Я недавно столкнулся с подобной ситуацией.Чтобы выполнить отладку в любой версии VS IDE, откройте исключения из Debug (Ctrl + D, E) - установите все флажки напротив столбца «Брошенный» и запустите приложение в режиме отладки.Я понял, что одна из таблиц не была должным образом импортирована в новую базу данных, поэтому внутреннее исключение Sql уничтожало соединение, что приводило к этой ошибке.

Суть истории в том, что если ранее работающий код возвращает эту ошибку в новой базе данных, это может быть проблема с отсутствующей схемой базы данных, осознайте из приведенного выше совета по отладке,

Hope It Helps, HydTechie

1 голос
/ 29 декабря 2016

Также проверьте, не выполняются ли какие-либо длительные процессы, выполняемые из вашего приложения .NET для БД. Например, вы можете вызывать хранимую процедуру или запрос, у которого недостаточно времени для завершения, что может отображаться в ваших журналах как:

  • Истекло время ожидания выполнения. Время ожидания истекло до завершение операции или сервер не отвечает.

    • Эта SqlTransaction завершена; его больше нельзя использовать.

Проверьте настройки тайм-аута команды Попробуйте запустить трассировку (профилировщик) и посмотреть, что происходит на стороне БД ...

0 голосов
/ 06 марта 2019

В моем случае у меня есть несколько кодов после фиксации транзакции в том же блоке try catch. ошибка может привести к тому, что выполнение перехватит блок, содержащий откат транзакции. Это покажет подобную ошибку. Например, посмотрите на структуру кода ниже:

SqlTransaction trans = null;

try{
 trans = Con.BeginTransaction();
// your codes

  trans.Commit();
//your codes having errors

}
catch(Exception ex)
{
     trans.Rollback(); //transaction roll back
    // error message
}

finally
{ 
    // connection close
}

Надеюсь, это кому-нибудь поможет:)

0 голосов
/ 11 февраля 2016

Вот способ обнаружить транзакцию Zombie

SqlTransaction trans = connection.BeginTransaction();

//some db calls here

if (trans.Connection != null) //Detecting zombie transaction
{
  trans.Commit();
}

Декомпилируя класс SqlTransaction, вы увидите следующее

public SqlConnection Connection
{
  get
  {
    if (this.IsZombied)
      return (SqlConnection) null;
    return this._connection;
  }
}

Я замечаю, что если соединение закрыто, transOP будетстать зомби, поэтому не может Commit.В моем случае это потому, что у меня есть Commit() внутри блока finally, а соединение было в блоке try.Такое расположение приводит к удалению соединения и сбору мусора.Решением было поместить Commit внутрь блока try.

...