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 打我的坏代码哈哈
简短的回答是,嵌套事务设计背后的意图是允许您编写可重用过程(或代码块)的代码,其中可以自动处理以下两种情况,而不必为两种情况编写不同的代码:
因此,假设您喜欢以事务方式对所有可重用过程进行编码,如下所示(伪代码):
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的内容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
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)
也就是说,如果其中一个过程忘记对称地启动和提交事务,嵌套事务仍然是危险的。
就我个人而言,我更喜欢在我的任何过程中都没有任何事务控制语句,而只让调用代码管理事务。这样我觉得安全多了。
| 归档时间: |
|
| 查看次数: |
12395 次 |
| 最近记录: |