"Эта SqlTransaction завершена; она больше не используется."... ошибка конфигурации?

Я работаю над этим уже около полутора дней и искал множество блогов и справочных статей в Интернете. Я нашел несколько вопросов, связанных с этой ошибкой, но я не думал, что они вполне применимы к моей ситуации (или в некоторых случаях, к сожалению, я не мог понять их достаточно хорошо, чтобы реализовать :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/).

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

7 ответов


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

ищите возможные области, где transacton совершается дважды (или откатывается дважды, или откатывается и совершается и т. д.). Фиксирует ли .Net-код транзакцию после того, как SP уже ее зафиксировал? Выполняет ли .Net-код откат при обнаружении ошибки, а затем пытается откатить его снова в предложении catch (или, наконец)?

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

можете ли вы отлаживать код ошибки? У вас есть трассировка стека?


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

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);
}

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


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

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

Надеюсь, Это Поможет, HydTechie


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

мой псевдо-код типа:

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();
}

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


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

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

    • эта SqlTransaction завершена; это больше не годный.

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


вот способ обнаружения транзакции зомби

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;
  }
}

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