#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’, оператор запрашивает что-то, что невозможно, когда процедура содержит ссылку на связанный сервер.