我今天偶然发现了这件事并且想知道一些事情。基本代码设置是
Begin Transaction
Update Table
set column to value
Begin transaction
Update Table
set column to value
我已经玩了一点,发现你做回滚后不能做提交,但是你可以在回滚之前做一个提交,但是回滚否定了提交。我想我的问题是,这有什么用途/用途吗?我没有看到其他人然后让我的DBA为我写错了代码lol
答案 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)
答案 2 :(得分:1)
您所做的是嵌套式转换。
这就是发生的事情: 如果您回滚内部事务,那么您也回滚最外层事务。另一方面,如果你提交了一个内部事务,你的数据修改就不会发生,直到最后的事务被提交为止。
更多信息here。
显然,在代码中使用嵌套事务根本没有意义。但想想这段代码:
BEGIN TRAN
UPDATE MyTable
SET Col1 = 'Val1';
EXEC dbo.SomeStoredProcedureUsingTransactions;
IF @@TRANCOUNT > 0
COMMIT TRAN;