Подтвердить что ты не робот

SQLTransaction завершила ошибку

Я получил следующую ошибку один раз в своем приложении.

Это SQLTransaction завершено; он больше не используется

След стека приведен ниже: он говорит о Zombie Check и Rollback.

Какая ошибка в коде?

Примечание. Эта ошибка появилась только один раз.

UPDATE

От MSDN - метод SqlTransaction.Rollback

Откат генерирует исключение InvalidOperationException, если соединение завершено или транзакция уже откатна на сервере.

От Проверка Zombie на транзакции - Ошибка

Одна из самых частых причин, по которым я обнаружил эту ошибку в различных приложениях, - это совместное использование SqlConnection в нашем приложении.

CODE

public int SaveUserLogOnInfo(int empID)
{
        int? sessionID = null;
        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            connection.Open();
            SqlTransaction transaction = null;
            try
            {
                transaction = connection.BeginTransaction();
                sessionID = GetSessionIDForAssociate(connection, empID, transaction);

                    //Other Code

                //Commit
                transaction.Commit();
            }
            catch
            {
                //Rollback
                if (transaction != null)
                {
                    transaction.Rollback();
                    transaction.Dispose();
                    transaction = null;
                }

                //Throw exception
                throw;
            }
            finally
            {
                if (transaction != null)
                {
                    transaction.Dispose();
                }
            }
        }

        return Convert.ToInt32(sessionID,CultureInfo.InvariantCulture);

   }

Трассировка стека

enter image description here


ССЫЛКА:


4b9b3361

Ответ 1

Вы должны оставить часть работы компилятору, чтобы обернуть это в try/catch/finally для вас.

Кроме того, вы должны ожидать, что Rollback может иногда генерировать исключение, если проблема возникает на этапе Commit или если соединение с сервером прерывается. По этой причине вы должны обернуть его в try/catch.

try
{
    transaction.Rollback();
}
catch (Exception ex2)
{
    // This catch block will handle any errors that may have occurred 
    // on the server that would cause the rollback to fail, such as 
    // a closed connection.
    Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
    Console.WriteLine("  Message: {0}", ex2.Message);
}

Это скопировано именно с страницы документации MSDN для метода отката.

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


От Метод MSDN - SqlTransaction.Rollback

Откат генерирует исключение InvalidOperationException, если соединение завершено или транзакция уже откатна на сервере.

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

Ответ 2

Примечание. Эта ошибка появилась только один раз.

тогда очень сложно сказать много; это может быть просто, что // Other Code и т.д. просто занял много времени, и вся вещь была убита. Возможно, ваша связь умерла, или администратор умышленно убил ее, потому что вы блокировали.

Какая ошибка в коде?

чрезмерное его усложнение; это может быть намного проще:

using (var connection = new SqlConnection(connectionString))
{
    connection.Open();
    using(var transaction = connection.BeginTransaction())
    {
        try
        {
            sessionID = GetSessionIDForAssociate(connection, empID, transaction);
            //Other Code
            transaction.Commit();
         }
         catch
         {
            transaction.Rollback();
            throw;
         }
    }
}

гораздо меньше кода, чтобы ошибиться.

Ответ 3

Я однажды испытал эту ошибку, и я застрял и не мог понять, что происходит. На самом деле я удалял запись, а в Хранимой процедуре я не удалял ее дочерний элемент, и особенно оператор delete в Stored Procedure находилась внутри границы Transaction. Я удалил этот код транзакции из хранимой процедуры и избавился от получения этой ошибки "This SqlTransaction has completed; it is no longer usable."

Ответ 4

Я использую приведенный ниже код, могу воспроизвести эту ошибку, я использую 1000 задач для выполнения Sql, после того, как примерно 300 задач успешно завершены, начинается множество исключений о timeout error на ExecuteNonQuery(),

то следующая ошибка This SqlTransaction has completed появится на transaction.RollBack();, а в стеке вызовов также будет ZombieCheck().

(Если одна программа с заданием 1000 задач недостаточно, вы можете одновременно выполнить несколько скомпилированных файлов exe или даже использовать несколько компьютеров для одной базы данных.)

Итак, я думаю, одна из причин, по которой эта ошибка может быть что-то неправильное в Connection, затем вызывает ошибку транзакции.

Task[] tasks = new Task[1000];
for (int i = 0; i < 1000; i++)
{
    int j = i;
    tasks[i] = new Task(() =>
         ExecuteSqlTransaction("YourConnectionString", j)
        );
}

foreach (Task task in tasks)
{
    task.Start();
}       

/////////////    

public void ExecuteSqlTransaction(string connectionString, int exeSqlCou)
{

    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();

        SqlCommand command = connection.CreateCommand();
        SqlTransaction transaction;

        // Start a local transaction.
        transaction = connection.BeginTransaction();

        // Must assign both transaction object and connection
        // to Command object for a pending local transaction
        command.Connection = connection;
        command.Transaction = transaction;

        try
        {
            command.CommandText =
                "select * from Employee";
            command.ExecuteNonQuery();

            // Attempt to commit the transaction.
            transaction.Commit();

            Console.WriteLine("Execute Sql to database."
                + exeSqlCou);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
            Console.WriteLine("  Message: {0}", ex.Message);


            // Attempt to roll back the transaction.
            try
            {
                transaction.Rollback();
            }
            catch (Exception ex2)
            {
                // This catch block will handle any errors that may have occurred
                // on the server that would cause the rollback to fail, such as
                // a closed connection.
                Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
                Console.WriteLine("  Message: {0}", ex2.Message);

            }
        }
    }
}

Кроме того, я обнаружил, что если я совершу дважды в секвенции, вы также вызовете это исключение.

       transaction.Commit();
       transaction.Commit();

Или если Connection Closed before commit также вызывает эту ошибку.

       connection.Close();
       transaction.Commit();

Update:

Мне странно, что я создаю новую новую таблицу и вставляю ей 500 тысяч данных,

затем используйте 100000 задач с select * from newtable sql, одновременно запустив 5 программ, на этот раз возникла ошибка таймаута, но когда transaction.Rollback() он не вызывал SQLTransaction has completed error.

но если произошла ошибка тайм-аута, перейдите в блок catch и в блоке catch снова выполните transaction.Commit(), произойдет SQLTransaction has completed error.

Ответ 5

Это сообщение просто потому, что вы написали код, который генерирует исключение после успешной транзакции . Пожалуйста, попробуйте проверить код, который вы написали после метода Commit или , который вы можете обрабатывайте его с помощью Try..Catch и, наконец, Blocks:).

Ответ 6

я столкнулся с той же проблемой, а затем решил ее. Попробуйте найти нежелательные соединения с потоком кода и используйте одно и то же соединение для всех кодов доступа db. :-)