Управление синонимами в процессе с вложенными процессами с помощью sp_getapplock - PullRequest
0 голосов
/ 30 июля 2011

Опираясь на темы, ранее затронутые gbn в этих вопросах Q1 , Q2 , Q3 , Q4 , а также относительно использования синонимов и повторного создания синонимов для сохранения синонимов, указывающих на живые данные, мне не ясно, как предотвратить «состояние гонки» с помощью

"sp_getapplock после BEGIN TRAN в режиме транзакции и перехватывать / обрабатывать статус возврата по мере необходимости."

Документация MSDN для sp_getapplock немного загадочна для меня. Например, может ли resource_name быть любой выдуманной строкой? Но более важно то, что если я запускаю один процесс, содержащий вложенные процессы, где первым шагом является построение таблиц, и если они успешны, то следующим важным шагом является DROP и CREATE существующих синонимов, как бы я правильно реализовать sp_getapplock?

CREATE PROCEDURE [dbo].[some_old_proc]   
AS  
SET XACT_ABORT, NOCOUNT ON

DECLARE     @nested_build_success varchar(3) = 'No' 
DECLARE     @starttrancount int

BEGIN TRY

    SET @starttrancount = @@TRANCOUNT

    IF      @starttrancount = 0
    BEGIN TRANSACTION
                -- fill the tables that the synonyms don't point to yet...
                EXEC    dbo.nested_proc_1       
                EXEC    dbo.nested_proc_2
                EXEC    dbo.nested_proc_3
                EXEC    dbo.nested_proc_4
                EXEC    dbo.nested_proc_5

        IF      @starttrancount = 0
        BEGIN  
            COMMIT TRANSACTION

            SET @nested_build_success = 'Yes'
        END

END TRY
BEGIN CATCH

    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION    
        -- RAISERROR... log error event   
END CATCH


IF  @nested_build_success = 'Yes'
BEGIN TRAN
        -- simple talk article
 -- http://www.simple-talk.com/sql/t-sql-programming/developing-modifications-that-survive-concurrency/

         DECLARE @ret INT    -- does it matter what the resource_name is?
          EXEC @ret = sp_getapplock @Resource = 'DoesNameMatterHere', @LockMode = 'Exclusive';

         IF @ret < 0
         BEGIN  
             -- log error message? 
         END
         ELSE
         BEGIN 
            -- call the proc that a does a DROP and CREATE of the relevant synonyms
        -- so the synonyms point at a different set of tables...
           EXEC dbo.change_the_synonyms      
         END

    COMMIT TRAN

Возможно, существует другой и лучший способ избежать состояния гонки, чем использование sp_getapplock, или доступен хороший пример того, что я пытаюсь сделать?

1 Ответ

2 голосов
/ 30 июля 2011

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

create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        EXEC sp_getapplock 'usp_my_procedure_name', 
                     'Exclusive', 
                     'TRANSACTION';

        EXEC    dbo.nested_proc_1;       
        EXEC    dbo.nested_proc_2;
        EXEC    dbo.nested_proc_3;
        EXEC    dbo.nested_proc_4;
        EXEC    dbo.nested_proc_5;

        EXEC    dbo.change_the_synonyms;

lbexit:
        if @trancount = 0   
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), 
                @message = ERROR_MESSAGE(), 
                @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 
                16, 1, @error, @message) ;
    end catch   
end

Это сделает всю работу атомарно. Он будет использовать блокировку приложения для сериализации доступа, чтобы никакие две процедуры не выполняли эту работу одновременно. В случае ошибки работа будет либо полностью откатываться, либо, если у вызывающей стороны уже есть транзакция, она откатывает работу до согласованного состояния при входе в процедуру без отката вызывающей стороны (это чрезвычайно полезно в пакетная обработка). XACT_ABORT имеет свое применение в сценарии развертывания, но смешивание XACT_ABORT с TRY / CATCH - это большая проблема в моей книге.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...