此存储过程中的Begin / Commit不匹配在哪里?

时间:2010-11-19 22:14:32

标签: sql sql-server database tsql stored-procedures

我收到以下错误:

EXECUTE之后的事务计数表示BEGIN和COMMIT语句的数量不匹配。先前的计数= 0,当前计数= 1.

当我尝试执行此存储过程时:

create procedure [dbo].[SynchCustomerSubscriptions] (
  @subscriptions Subscriptions readonly )
as

begin transaction

begin tran SynchTransaction
  begin try
    delete s
    from Subscription s (nolock)
    where s.Customer in (
      select Customer
      from @subscriptions)
    exec AddSubscriptions
      @subscriptions
  end  try
  begin catch
    rollback tran SynchTransaction
    return
  end  catch
commit tran SynchTransaction

有没有人发现问题?

3 个答案:

答案 0 :(得分:3)

begin transaction 

begin tran SynchTransaction 

有时候你看这些东西太久了,最简单的事情就是逃避你。

答案 1 :(得分:0)

试试这个......

create procedure [dbo].[SynchCustomerSubscriptions] (    
  @subscriptions Subscriptions readonly )    
as    

begin transaction SynchTransaction    

begin tran    
  begin try    
    delete s    
    from Subscription s (nolock)    
    where s.Customer in (    
      select Customer    
      from @subscriptions)    
    exec AddSubscriptions    
      @subscriptions    
  end  try    
  begin catch    
    rollback tran SynchTransaction    
    return    
  end  catch    
end tran
commit transaction SynchTransaction  

答案 2 :(得分:0)

在存储过程中启动命名的事务实际上非常糟糕。如果在另一个事务的范围内调用该过程,则不可能仅回滚命名事务,如您明显尝试的那样,请参阅MSDN

  

在a中命名多个事务   一系列带嵌套的事务   事务名称影响不大   交易。只有第一个   (最外面)的交易名称是   在系统注册。回滚   任何其他名称(有效的除外)   保存点名称)生成错误。

你可能想要的是一个保存点,它是一种不同的野兽。如果要混合嵌套事务,保存点和异常try / catch块,事情就会复杂一些。最好使用类似于本文Exception handling and nested transactions的模式,该模式考虑当前@@TRANCOUNT和异常XACT_STATE

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;

        -- Do the actual work here

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) ;
        return;
    end catch   
end