本文介绍了回滚游标内和事务内的事务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 T-SQL 的新手,我在处理一些包含事务、游标和存储过程的大型脚本方面遇到了麻烦.所以,我的代码是这样的(这段代码只是我的脚本结构的一个例子,实际上我在 OuterProc 游标中有多个过程,在 InnerProc 游标中有多个操作):

I'm pretty new in T-SQL and I'm in trouble with some huge scripts with transactions, cursors and storage procedures. So, my code is something like this (this code is just an example of the structure of my scripts, in fact I have multiples procedures inside OuterProc cursor and multiple operations inside InnerProc cursor):

create proc InnerProc
as
begin
  declare @Id int

  begin tran

  declare mycursor cursor local static read_only forward_only
  for select Id
      from MyOtherTable

  open mycursor
  fetch next from mycursor into @Id

  while @@fetch_status = 0
  begin
    select 1/0

    if @@ERROR <> 0
    begin
      rollback tran
      return @@ERROR
    end

    fetch next from mycursor into @Id
  end

  close mycursor
  deallocate mycursor

  commit tran
end


create proc OuterProc
as
begin

  declare @Id int

  begin tran

  declare mycursor cursor local static read_only forward_only
  for select Id
      from MyTable

  open mycursor
  fetch next from mycursor into @Id

  while @@fetch_status = 0
  begin
    exec @error = InnerProc

    if @@ERROR <> 0
    begin
      rollback tran
      return
    end
    else
      commit tran

    fetch next from mycursor into @Id
  end

  close mycursor
  deallocate mycursor
end

使用这个结构我有这个错误:

With this structure I have this error:

Msg 515, Level 16, State 2, Procedure InnerProc, Line 448
  Cannot insert the value NULL into column 'InitialQuantity', table 'MySecondTable'; column does not allow nulls. INSERT fails.
  The statement has been terminated.
Msg 266, Level 16, State 2, Procedure InnerProc, Line 0
  Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.
Msg 3903, Level 16, State 1, Procedure CreateSASEExtraction, Line 79
  The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.

我的代码有什么问题?如果innerProc 内部出现问题,我希望该外部游标的所有操作都回滚并停止内部游标.如果outerProc 出现问题,我希望该游标的所有操作都回滚,但我希望该游标继续循环......
有更好的方法吗?

What is wrong with my code? If something goes wrong inside innerProc, I want all operations for that outer cursor rollback and stop the inner cursor. If something goes wrong in the outerProc I want all operations for that cursor to rollback but I want that cursor continue to looping...
There is a better way to do this?

更新:

在纠正@Bernd Linde 检测到的一些错误后,我在 InnerProc 中添加了一个 try-catch 并将该事务命名为 InnerProc.现在我有这个代码:

After I correct some errors @Bernd Linde detected, I add a try-catch in InnerProc and I named the InnerProc transaction. Now I have this code:

create proc InnerProc
as
begin
  declare @Id int

  begin tran

  begin try

    declare mycursor cursor local static read_only forward_only
    for select Id
        from MyOtherTable

    open mycursor
    fetch next from mycursor into @Id

    while @@fetch_status = 0
    begin
      select 1/0

      if @@ERROR <> 0
        return @@ERROR

      fetch next from mycursor into @Id
    end

    close mycursor
    deallocate mycursor

    commit tran
    return 0

  end try
  begin catch

    return @@ERROR

  end catch

end


create proc OuterProc
as
begin

  declare @Id int

  declare mycursor cursor local static read_only forward_only
  for select Id
      from MyTable

  open mycursor
  fetch next from mycursor into @Id

  while @@fetch_status = 0
  begin

    begin tran

    exec @error = InnerProc

    if @@ERROR <> 0
    begin
      rollback tran
      return
    end
    else
      commit tran

    fetch next from mycursor into @Id
  end

  close mycursor
  deallocate mycursor
end

但现在我有其他错误信息:

But now I have other error message:

Msg 266, Level 16, State 2, Procedure InnerProc, Line 0
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 2.

我该如何解决这个问题?

How can I solve this?

推荐答案

经过多次尝试,我终于明白了.

After many attemps, finally I get it.

InnerProc 必须只有 COMMIT,OuterProc 将负责回滚.为此,当 InnerProc 导致一些必须在 OuterProc 中捕获并被迫像异常一样的错误时.我想如何在 OuterProc 中继续循环,该过程必须有一个 try-catch,其中强制循环并完成回滚.

The InnerProc must only have COMMITs and the OuterProc will be responsible for rollback.For that, when InnerProc causes some error that must be catch in the OuterProc and forced to act like a exception.How I want to continue looping in the OuterProc, that procedure must have a try-catch where the looping is forced and the rollback is done.

为了更好地控制交易数量,我使用了@@TRANCOUNT.

For a better transaction number control I used the @@TRANCOUNT.

所以我用这段代码解决了这个问题:

So I solve the problem with this code:

create proc InnerProc
as
begin
  declare @Id int

  begin try

  begin tran

    declare mycursor cursor local static read_only forward_only
    for select Id
        from MyOtherTable

    open mycursor
    fetch next from mycursor into @Id

    while @@fetch_status = 0
    begin
      select 1/0

      IF @@ERROR <> 0
      begin

        if @@TRANCOUNT > 0
          rollback tran

        close mycursor
        deallocate mycursor
        return @@ERROR

      end

      fetch next from mycursor into @Id

    end

    close mycursor
    deallocate mycursor

    commit tran
    return 0

    end try
    begin catch

        close mycursor
        deallocate mycursor

        return @@ERROR
    end catch

end


create proc OuterProc
as
begin

  declare @Id int

  declare mycursor cursor local static read_only forward_only
  for select Id
      from MyTable

  open mycursor
  fetch next from mycursor into @Id

  while @@fetch_status = 0
  begin

    begin tran

    begin try

      exec @error = InnerProc

      if @@ERROR <> 0
          RAISERROR('Exception',1,1)


      if@@TRANCOUNT > 0
          commit tran

      fetch next from mycursor into @Id, @Name, @CodeDGAE, @Code, @NUIT, @Project

    end try
    begin catch
        if @@TRANCOUNT > 0
            rollback tran
        fetch next from mycursor into @Id, @Name, @CodeDGAE, @Code, @NUIT, @Project
    end catch
  end

  close mycursor
  deallocate mycursor
end

这篇关于回滚游标内和事务内的事务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-08 20:00