Действительно ли мне нужно использовать "SET XACT_ABORT ON"?

если вы будете осторожны и используете TRY-CATCH вокруг всего, и откатитесь от ошибок, вам действительно нужно использовать:

SET XACT_ABORT ON

Другими словами, есть ли какие-либо ошибки, которые TRY-CATCH пропустят, что SET XACT_ABORT ON будет обрабатывать?

Ответ 1

Помните, что есть ошибки, которые TRY-CATCH не будет захватывать с помощью или без XACT_ABORT.

Однако SET XACT_ABORT ON не влияет на захват ошибок. Это гарантирует, что любая транзакция откатывается/обречена. Когда "ВЫКЛ", у вас все еще есть выбор фиксации или откат (с учетом xact_state). Это основное изменение поведения SQL 2005 для XACT_ABORT

То, что он также делает, это удалить блокировки и т.д., если истекает время ожидания команды клиента, и клиент отправляет директиву "abort". Без SET XACT_ABORT блокировки могут оставаться, если соединение остается открытым. Мой коллега (MVP) и я тщательно проверили это в начале года.

Ответ 2

Я считаю, что SET XACT_ABORT ON является требованием при выполнении распределенных транзакций.

Из книг онлайн: XACT_ABORT должен быть установлен в ON для операторов модификации данных в неявной или явной транзакции против большинства поставщиков OLE DB, включая SQL Server. Единственный случай, когда эта опция не требуется, заключается в том, что поставщик поддерживает вложенные транзакции. Дополнительные сведения см. В разделе Распределенные запросы и распределенные транзакции.

Ответ 3

XACT_ABORT действительно влияет на обработку ошибок: он прервет всю партию при возникновении ошибки, и любой код, следующий за строкой, которая вызвала ошибку (включая проверку ошибок!), НИКОГДА не будет выполняться. Существует два исключения из этого поведения: XACT_ABORT заменяется на TRY... CATCH (блок CATCH всегда будет выполняться, а транзакции НЕ будут откатываться автоматически, только отображаются неумелыми), а XACT_ABORT игнорирует RAISERROR.

Ответ 4

Я понимаю, что даже если используется catch catch, и в блоке catch не используется оператор rollback, любая неприемлемая транзакция будет отменена, когда XACT_ABORT будет включен.

Ответ 5

Существует оговорка, чтобы слепо всегда использовать SET XACT_ABORT ON; который недавно сожгли меня.

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

begin transaction
try
    perform insert
    catch duplicate key violation and react appropriately

    perform more actions

    commit transaction
catch
    rollback transaction
end

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

begin transaction
try
    perform insert
    catch duplicate key violation and react appropriately
    transaction implicitly rolled back

    perform more actions

    commit transaction -> fails because not in a transaction
catch
    rollback transaction -> fails because not i a transaction
end

С тех пор меня перевернули. Никогда используйте SET XACT_ABORT ON.


Изменить. Люди, похоже, думают, что проблема связана с попыткой вызвать ROLLBACK TRANSACTION, а не в транзакции. Они думают, что проблему можно устранить, не вызвав ROLLBACK, если транзакция не выполняется.

Позвольте использовать некоторый псевдокод, с изменениями имен для защиты NDA:

const
   SQLNativeErrorPrimaryKeyViolation = 2627; //Primary keys. 2601 is for other unique index

void x(String sql)
{
   database.Connection.ExecuteNoRecords(sql);
}

который является педантичным способом сделать этот ответ более удобочитаемым; мы используем x для представления eXecution некоторого оператора SQL:

void DoStuff()
{
   x("BEGIN TRANSACTION");
   try
   {
      try
      {
         x("INSERT INTO Patrons (AccountNumber, Name, Gender)"+
           "VALUES (619, 'Shelby Jackson', 'W'"); 
      } 
      catch (ESqlServerException e)
      {
         //check if the patron already exists (or some other hypothetical situation arises)
         if (e.NativeError == SQLNativeErrorPrimaryKeyViolation)
         {
            //This patron already exists. Set their frob to grob because contoso the blingblong
            x("UPDATE Patrons SET Frob='Grob' WHERE AccountNumber = 619");

            //20110918: Dont forget we also need to bang the gardinker
            x("EXECUTE BangTheGardinker @floof=619");
         }
         else
            throw e;
      }

      //Continue with the stuff
      x("EXECUTE Frob('{498BBB4D-D9F7-4438-B7A6-4AB5D57937C0}')");

      //All done, commit the transaction
      x("COMMIT TRANSACTION");       
   }
   catch (Exception e)
   {
      //Something bad happened, rollback the transaction 
      //(if SQL Server didn't kill the transaction without our permission)
      x("IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION");


      throw e;
   }
}

XACT_ABORT ON классный, позволяет использовать его

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

Теперь давайте посмотрим, следите ли мы за тем, чтобы XACT_ABORT всегда был включен:

 DbConnection Connection()
 {
    if (_connection == null)
    {
       _connection = new SqlConnection();

       //It is generally recommended that you always have xact_abort on.
       //If a connection is closed with a transaction still in progress
       //it still leaves locks held until that connection is finally recycled
       //Also, when querying linked severs in a client-side transaction, the
       //operation won't work until xact_abort is on (SQL Server will throw an saying xactabort is off
       _connection.ExecuteNoRecords("SET XACT_ABORT ON");
    }

    return _connection;
 }

void x(String sql)
{
   database.Connection.ExecuteNoRecords(sql);
}

Вы видите повреждение, которое приведет к DoStuff?

DoStuff был правильно написан для обработки ошибок. Но введение XACT_ABORT ON в соединение теперь приведет к повреждению базы данных. Для тех из вас, кто не видит ошибку, пропустите код:

void DoStuff()
{
   x("BEGIN TRANSACTION");
   try
   {
      try
      {
         x("INSERT INTO Patrons (AccountNumber, Name, Gender)"+
           "VALUES (619, 'Shelby Jackson', 'W'"); 

      } 
      catch (ESqlServerException e)
      {
         //WARNING: WE ARE NO LONGER OPERATING IN A TRANASCTION
         //Because XACT_ABORT is on, the transaction that we started has been implicitly rolled back.
         //From now on, we are no longer in a transaction. If another error happens
         //the changes we make cannot be rolled back

         //check if the patron already exists (or some other hypothetical situation arises)
         if (e.NativeError == SQLNativeErrorPrimaryKeyViolation)
         {
            //WARNING: This update happens outside of any transaction!
            //This patron already exist. Set their frob to grob because contoso the blingblong
            x("UPDATE Patrons SET Frob='Grob' WHERE AccountNumber = 619");

            //WARNING: This stored procedure happens outside of any transaction!
            //20110918: Dont forget we also need to bang the gardinker
            x("EXECUTE BangTheGardinker @floof=619");
         }
         else
            throw e;
      }

      //WARNING: This stored procedure happens outside of any transaction!
      //If any error happens from
      //Continue with the stuff
      x("EXECUTE Frob('{498BBB4D-D9F7-4438-B7A6-4AB5D57937C0}')");

      //WARNING: This stored procedure happens outside of any transaction. It will throw:
      //   Msg 3902, Level 16, State 1, Line 1
      //   The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
      //All done, commit the transaction
      x("COMMIT TRANSACTION");       
   }
   catch (Exception e)
   {
      //If there was an error during Frob, we would want to catch it and roll everything back.
      //But since SQL Server ended the transaction, we have no way to rollback the changes

      //And even if the call to Frob (or Updating the patron Grob, or Banging the Gardinder)
      //didn't fail, the call to COMMIT TRANSACTION will throw an error

      //Either way, we have detected an error condition that cannot be rolled back in the database


      //Something bad happened, rollback the transaction 
      //(if SQL Server didn't kill the transaction without our permission)
      x("IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION");


      throw e;
   }
}

Код, который был написан правильно и работает, становится сломанным, вызывает ошибки и в худшем случае вызывает повреждение базы данных. Все, потому что я включил XACT_ABORT ON.

Ответ 6

Когда XACT_ABORT установлен в OFF в триггере, и я вызываю RAISEERROR в корпусе триггера, изменения не откатываются назад.