Сбой выполнения хранимой процедуры при размещении в транзакции

#sql-server #tsql

#sql-server #tsql

Вопрос:

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

 USE db1;

SET xact_abort ON;

DECLARE @statement NVARCHAR(max);
SET @statement = 'EXECUTE (''INSERT INTO T1(V1, V2) VALUES (1, 2)'') AT LS1';

BEGIN try
    BEGIN TRANSACTION

    EXEC Sp_executesql @statement

    COMMIT TRANSACTION
END try

BEGIN catch
    IF ( Xact_state() ) = -1
      BEGIN
          PRINT Error_message()

          ROLLBACK TRANSACTION
      END

    IF ( Xact_state() ) = 1
      BEGIN
          PRINT 'COMMIT OPEN TRANSACTION'

          COMMIT TRANSACTION
      END

    INSERT INTO tblerrmsg (errornumber, errorseverity, errorstate, errorline, errormessage) EXECUTE Usp_geterrorinfo;
END catch
  

Это приводит к сбою с записью в моей таблице TblErrMsg.

Номер ошибки = 8501, уровень ошибки = 16, Состояние ошибки = 3, строка ошибки = 1, сообщение об ошибке = MSDTC на сервере ‘XXX’ недоступен.

Итак, я исследовал конкретное сообщение об ошибке и проверил, запущена ли служба координатора распределенных транзакций на сервере, но это уже имело место. Даже перезапуск службы не привел к каким-либо изменениям. Затем я попытался удалить транзакцию и выполнить следующую процедуру:

 USE db1;

DECLARE @statement NVARCHAR(max);
SET @statement = 'EXECUTE (''INSERT INTO T1(V1, V2) VALUES (1, 2)'') AT LS1';

BEGIN try
    EXEC Sp_executesql @statement
END try

BEGIN catch
    PRINT Error_message()
END catch
  

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

У кого-нибудь когда-либо была подобная проблема или есть объяснение такого поведения?

Комментарии:

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

2. К сожалению, я все еще не понимаю, почему транзакция действительно завершается с ошибкой. Ошибка просто сообщает мне, что MSDTC не запущен, что не так. В случае недопустимой процедуры, не должна ли быть ошибка и во втором случае (без транзакции)? Или есть другая причина ошибки «MSDTC на сервере»XXX»недоступен», которую я не рассматривал?

Ответ №1:

Возможно, вы упускаете ключевое слово DISTRIBUTED при указании явной транзакции.

Вместо

 BEGIN TRANSACTION
  

Попробуйте

 BEGIN DISTRIBUTED TRANSACTION
  

Согласно документам, это способ указать «… запуск распределенной транзакции Transact-SQL, управляемой координатором распределенных транзакций Microsoft (MS DTC)»

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

Когда BEGIN TRANSACTION указана без ‘DISTRIBUTED’, оператор запрашивает что-то, что невозможно, когда процедура содержит ссылку на связанный сервер.