Сбой COMMIT TRANSACTION для связанного сервера при TRY CATCH - PullRequest
0 голосов
/ 26 декабря 2018

Я работаю с Linked Server, и этот код работает нормально

BEGIN TRY
    INSERT INTO [Dev].[dbo].tb_test (no)  SELECT no from [MYLINKEDSERVER].[mydb].[dbo].tb_test 
    DELETE FROM [MYLINKEDSERVER].[mydb].[dbo].tb_test
END TRY
BEGIN CATCH
    SELECT 'fail'
END CATCH

, но когда я использую его с COMMIT TRANSACTION, вот так

BEGIN TRY
    BEGIN TRANSACTION 
    INSERT INTO [Dev].[dbo].tb_test (no)  SELECT no from [MYLINKEDSERVER].[mydb].[dbo].tb_test 
    DELETE FROM [MYLINKEDSERVER].[mydb].[dbo].tb_test
    COMMIT
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK
END CATCH

показать ошибку

Поставщик OLE DB «SQLNCLI11» для связанного сервера «MYLINKEDSERVER» вернул сообщение «Менеджер транзакций партнера отключил свою поддержку удаленных / сетевых транзакций.».

Что не так?

Ответы [ 3 ]

0 голосов
/ 26 декабря 2018

Попробуйте это должно работать

DECLARE @ServerName SYSNAME
, @Message nvarchar(1000)
, @CMD1 nvarchar(max)
--
DECLARE @Server_List Table
( SrvID SMALLINT
, SrvName SYSNAME )
--
Set NoCount ON
--
-- Load up linked server list
--
BEGIN
INSERT INTO @Server_List (SrvID, SrvName)
SELECT SrvID
, SrvName 
FROM [master].[SYS].sysservers
ORDER BY SrvID ASC
END
--
SELECT TOP 1 @ServerName = SrvName
FROM @Server_List
ORDER BY SrvID ASC
--
-- Loop through the Linked Server List
--
WHILE EXISTS ( SELECT * FROM @Server_List )
BEGIN
SELECT @Message = 'Server Name is '+ @ServerName
--
RAISERROR (@Message, 10,1) WITH NOWAIT
--
SET @CMD1 = 'EXEC master.dbo.sp_serveroption @server=N'''
+ @ServerName
+ ''', @optname=N''rpc'', @optvalue=N''true'''
Exec sp_executesql @cmd1
--
SET @CMD1 = 'EXEC master.dbo.sp_serveroption @server=N'''
+ @ServerName
+ ''', @optname=N''rpc out'', @optvalue=N''true'''
Exec sp_executesql @cmd1
--
set @cmd1 = 'EXEC master.dbo.sp_serveroption @server = '''
+ @ServerName
+ ''', @optname=N''remote proc transaction promotion'', @optvalue=N''false'''
Exec sp_executesql @stmt=@cmd1,@params=N''
--
DELETE FROM @Server_List WHERE SrvName = @ServerName
--
SELECT TOP 1 @ServerName = SrvName
FROM @Server_List
ORDER BY SrvID ASC
--
END 
0 голосов
/ 27 декабря 2018

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

BEGIN TRY
BEGIN TRANSACTION 
    INSERT INTO [Dev].[dbo].tb_test (no)  
        SELECT no 
        FROM [MYLINKEDSERVER].[mydb].[dbo].tb_test 

    DECLARE @returnvalue INT

    EXEC @returnvalue = [MYLINKEDSERVER].[mydb].[dbo].sp_update @no

    IF @returnvalue = 1
    BEGIN
        COMMIT
    END
    ELSE 
    BEGIN
        ROLLBACK
    END
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK
END CATCH

Хранимая процедура:

CREATE PROCEDURE [dbo].[sp_update] 
     @no NVARCHAR(20)
AS
BEGIN
    SET NOCOUNT ON

    BEGIN TRY
        BEGIN TRANSACTION
            DELETE FROM mytb 
            WHERE no = @no

            COMMIT
            RETURN 1
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK
        RETURN 0
    END CATCH
END

Надеюсь помочь кому-нибудь

0 голосов
/ 26 декабря 2018

Попробуйте выполнить приведенную ниже команду на сервере, на котором вы собираетесь выполнить операцию вставки.

EXEC sp_serveroption @server = 'ReadServerName',@optname = 'remote proc transaction promotion', @optvalue = 'false' ;

Также попробуйте выполнить приведенный ниже код.Я добавил BEGIN DISTRIBUTED TRANSACTION вместо BEGIN TRANSACTION.

BEGIN TRY
    BEGIN DISTRIBUTED TRANSACTION
    INSERT INTO [Dev].[dbo].tb_test (no)  SELECT no from [MYLINKEDSERVER].[mydb].[dbo].tb_test 
    DELETE FROM [MYLINKEDSERVER].[mydb].[dbo].tb_test
    COMMIT
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK
END CATCH

Подробности доступны на MS site .

...