使用sp_getapplock管理具有嵌套过程的proc中的同义词

时间:2011-07-30 01:52:11

标签: sql sql-server tsql sql-server-2008

gbn先前在这些问题中提到的主题为基础 Q1Q2Q3Q4,关于使用同义词和重新创建同义词以保持同义词指向实时数据,目前尚不清楚我如何使用

来防止“竞争条件”
  

“事务模式下BEGIN TRAN之后的sp_getapplock并根据需要陷阱/处理返回状态。”

sp_getapplock的MSDN文档对我来说有点神秘。例如,resource_name可以是任何组成的字符串吗?但更重要的是:如果我运行包含嵌套过程的单个过程,第一步是构建表,如果这些成功,那么下一个主要步骤是DROPCREATE现有的同义词,我将如何正确实现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 个答案:

答案 0 :(得分:2)

如果我正确理解您的问题,准备步骤和同义词设置必须在单个事务中,而不是两个单独的事务。以下是基于Exception handling and nested transactions模板的示例:

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

这将以原子方式完成所有工作。它将使用applock来序列化访问,这样就不会有两个程序同时执行这项工作。如果出现错误,工作将完全回滚,或者在调用者已经有事务的情况下,它将工作回滚到过程条目的一致状态,而不回滚调用者(这在批量处理)。 XACT_ABORT在部署脚本中有用,但在我的书中将XACT_ABORT与TRY / CATCH混合是一个很大的禁忌。