多个开始事务

Hol*_* IV 3 sql sql-server sql-server-2008

我今天遇到了这个意外,并想知道一些事情。基本的代码设置是

Begin Transaction 
Update Table
set column to value

Begin transaction
Update Table
set column to value
Run Code Online (Sandbox Code Playgroud)

我玩了一点,发现你不能在回滚后进行提交,但你可以在回滚之前进行提交,但是回滚会否定提交。我想我的问题是,这有什么目的/用途吗?我没有看到其他然后让我的 DBA 打我的坏代码哈哈

sst*_*tan 5

简短的回答是,嵌套事务设计背后的意图是允许您编写可重用过程(或代码块)的代码,其中可以自动处理以下两种情况,而不必为两种情况编写不同的代码:

  • 如果还没有开始事务,您可以开始和结束事务。
  • 或者,如果交易已经在进行中,那么您只需参与正在进行的交易。

因此,假设您喜欢以事务方式对所有可重用过程进行编码,如下所示(伪代码):

create procedure Foo
    begin transaction

    perform DML 1
    perform DML 2
    perform DML 3
    -- other stuff

    commit transaction
end procedure

create procedure Blah
    begin transaction

    perform DML 1
    perform DML 2
    perform DML 3
    -- other stuff

    commit transaction
end procedure
Run Code Online (Sandbox Code Playgroud)

但是现在,假设您现在需要该Blah程序来合并什么Foo。显然,您不想复制粘贴Fooin的内容BlahFoo为了可重用性,一个简单的调用更有意义,如下所示:

create procedure Blah
    begin transaction

    perform DML 1
    perform DML 2

    -- include a call to Foo here
    Foo();

    perform DML 3
    -- other stuff

    commit transaction
end procedure
Run Code Online (Sandbox Code Playgroud)

在上述情况下,无需对Foo的代码进行任何更改,对 的调用Blah仍将表现为一个大事务,这可能正是您想要的。

正是在这种情况下,inners commit实际上不做任何事情。它们实际上只是为了表明在那之前一切都很好。但真正的提交只有在外部事务提交所有内容时才会发生。

想象一下,如果每次提交实际上都提交了事务,那么,为了确保您不会破坏外部事务,您必须在每个过程的开头添加额外的条件来检查事务是否已经启动,并且只启动一个如果没有找到。因此,每个过程都必须像这样编码,以确保在其他过程中调用是安全的:

create procedure Foo
    didIStartATransaction = false
    if @@trancount = 0 then
      begin transaction
      didIStartATransaction = true
    end if

    perform DML 1
    perform DML 2
    perform DML 3
    -- other stuff

    if didIStartATransaction then
      commit transaction
    end if
end procedure

create procedure Blah
    didIStartATransaction = false
    if @@trancount = 0 then
      begin transaction
      didIStartATransaction = true
    end if

    perform DML 1
    perform DML 2
    perform DML 3
    -- other stuff

    if didIStartATransaction then
      commit transaction
    end if
end procedure
Run Code Online (Sandbox Code Playgroud)

也就是说,如果其中一个过程忘记对称地启动和提交事务,嵌套事务仍然是危险的。

就我个人而言,我更喜欢在我的任何过程中都没有任何事务控制语句,而只让调用代码管理事务。这样我觉得安全多了。