16

我在 sql 中有一个循环,它做一些事情

    begin tran one

    do some inserts in others tables

      --start loop
     begin tran two
      --do something
      begin try
--if something fail then a trigger does rollback and this return a error (and this goes to catch), then don't i need do the rollbak in catch? this could not be dissable because this is working on production
      --something finished ok 
      commit tran two
      end try
      begin catch
     rollback tran two
      end catch

    --finished loop
    commit


----------

我收到了这个错误

在批处理结束时检测到不可提交的事务。事务被回滚。

begin tran one
begin tran two

rollback tran two

做这个代码我得到这个:

不能回滚两个。未找到该名称的事务或保存点。

我只希望子查询回滚第二个循环并继续处理其他记录。

4

2 回答 2

14

操作员回滚回滚所有事务,对于仅回滚第二个循环,您必须使用保存点:

  begin tran one

-- do some inserts in others tables

  --start loop
  save tran two -- begin tran two

  --do something
  begin try
     update product set id = 1 --if something fail then a trigger does rollback and this return a error (and this goes to catch), then don't i need do the rollbak in catch? this could not be dissable because this is working on production

  --something finished ok 
  commit tran two
  end try
  begin catch

    rollback tran two
  end catch

--finished loop
commit

触发示例:

create table product (id int)
GO  
create trigger product_trigger on product for update
as
  set xact_abort off

  if (select count(*) from inserted i join product p on i.id=p.id)=0 begin 
    if (@@trancount>0) begin 
      /* rollback */ 
      raiserror('product does not exist', 16, 1) 
    end 
  end
于 2013-10-09T11:54:46.737 回答
5

就我而言,我的代码是否通过EF DbContext方法调用了一个 SQL Server 存储过程,其中包含一个非嵌套事务。

因为,正如@NotMe 已经指出的那样,“ SQL Server 中没有嵌套事务”,我开始怀疑我的进程是否真的是无事务嵌套的。

怀疑我的 DbContext 有一些内疚,我开始检查 DbContext 选项,直到DbContext.Configuration.EnsureTransactionsForFunctionsAndCommands = True引起了我的注意。

因此,只要我将其值更改为True,一切都会成功。

MyDbContext.Configuration.EnsureTransactionsForFunctionsAndCommands = false;

发生了什么?

好吧,在我看来,EF 的ObjectContext.ExecuteFunction方法将其自己的外部事务作为我的存储过程的内部事务的包装器来管理,因此,当我的存储过程的 ROLLBACK TRAN 被命中时,当 EF 的 COMMIT/ROLLBACK 代码为打。

奇怪的是,在收集有关EnsureTransactionsForFunctionsAndCommands属性的一些引用时,我发现这种默认行为是由于 EF 团队有史以来最糟糕的决定之一(在我看来),因为它与 T-SQL 脚本中的每个 ROLLBACK TRAN 直接冲突。

有关 EF 的更多详细信息,请查看insightfull SO 在EF6 的 QA 将每个存储过程调用包装在其自己的事务中。如何防止这种情况?

基本上,每个人都应该@@trancount > 0在发出ROLLBACK命令之前进行检查,无论是否命名,特别是在存储过程中。

CREATE PROCEDURE Proc1 AS
BEGIN
    BEGIN TRAN
    EXEC Proc2
    IF(@@trancount > 0)
        COMMIT TRAN
END

CREATE PROCEDURE Proc2 AS
BEGIN
    BEGIN TRAN
    ROLLBACK TRAN
END

为了更好地了解Microsoft SQL Server的嵌套事务,我建议阅读以下文章 在 SQL Server 中的嵌套事务上小心使用 ROLLBACK!

希望它可以帮助某人:-)

于 2018-07-28T01:57:31.440 回答