多个开始交易

时间:2015-07-07 19:38:23

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

我今天偶然发现了这件事并且想知道一些事情。基本代码设置是

Begin Transaction 
Update Table
set column to value

Begin transaction
Update Table
set column to value

我已经玩了一点,发现你做回滚后不能做提交,但是你可以在回滚之前做一个提交,但是回滚否定了提交。我想我的问题是,这有什么用途/用途吗?我没有看到其他人然后让我的DBA为我写错了代码lol

3 个答案:

答案 0 :(得分:4)

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

  • 如果尚未启动任何交易,您可以开始和结束交易。
  • 或者,如果交易已在进行中,那么您只需参与正在进行的交易。

所以,让我们假设您希望以事务方式编写所有可重用的过程,如下所示(伪代码):

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

但现在,让我们说您现在需要Blah程序来合并Foo所做的事情。显然,您不希望在Foo中复制粘贴Blah的内容。对Foo的简单调用对于可重用性更有意义,例如:

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

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

对于像这样的情况, 内部 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

也就是说,如果其中一个程序忘记了对称启动和提交事务,那么嵌套事务仍然会很危险。

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

答案 1 :(得分:1)

请查看SAVEPOINT语法。这允许您在可以回滚到的事务中设置点。

javadocs

你的答案是:)

答案 2 :(得分:1)

您所做的是嵌套式转换

这就是发生的事情: 如果您回滚内部事务,那么您也回滚最外层事务。另一方面,如果你提交了一个内部事务,你的数据修改就不会发生,直到最后的事务被提交为止。

更多信息here

显然,在代码中使用嵌套事务根本没有意义。但想想这段代码:

BEGIN TRAN

UPDATE MyTable
SET Col1 = 'Val1';

EXEC dbo.SomeStoredProcedureUsingTransactions;

IF @@TRANCOUNT > 0
    COMMIT TRAN;