Sql server 在事务的捕获范围内,@trancount怎么可能为零?

Sql server 在事务的捕获范围内,@trancount怎么可能为零?,sql-server,transactions,try-catch,Sql Server,Transactions,Try Catch,我有一个带有事务和try/catch的语句块: begin try begin transaction; insert .... update .... delete .... commit transaction; end try begin catch if (@@trancount > 0) rollback transaction; throw; end catch; 我在这里使用的是

我有一个带有事务和try/catch的语句块:

begin try
    begin transaction;
        insert ....
        update ....
        delete ....
    commit transaction;
end try
begin catch
    if (@@trancount > 0)
        rollback transaction;
    throw;
end catch;
我在这里使用的是
@@trancount
,但没有完全理解发生了什么。
在这种情况下,为什么会发生
@@tracount
为零的情况呢?

最常见的接收
@@tracount=0
的场景需要比示例使用的更详细的逻辑

如果在
try
块中调用了其他存储过程,则它们可能对如何管理事务有自己的理解,并且由于编写的代码不好或其他一些问题,它们可能会意外地提交外部事务,或者将其回滚(请记住,任何不引用以前声明的保存点的
rollback
语句都会清除所有内容)。在这种情况下,错误可能会有所不同,可能是导致内部过程首先出现错误,或者如果没有其他错误,您将得到,执行后的事务计数表示BEGIN和COMMIT语句的数目不匹配。上一个计数=%ld,当前计数=%ld

请注意,此行为也可能由触发器执行的回滚引起

当您在
catch
块中没有当前事务时,可能会出现其他一些情况,但显然这些情况非常罕见,我想不出还有什么其他情况

就我个人而言,我尽可能对所有存储过程使用以下模板:

创建过程dbo.ProcTemplate
(
@错误int=null输出,
@消息nvarchar(2048)=空输出
)作为
/*
20191223,RW-待完成
*/
设置nocount、quoted_标识符、ansi_空值、ansi_警告、ansi_填充、concat_空值、arithabort on;
设置xact\u abort、隐式\u事务、数值\u roundabort关闭;
声明@XTran bit=cast(符号(@@tracount)为位);
开始尝试
如果@XTran=0
开始训练;
--把你的代码放在这里
如果@XTran=0
犯罪
结束尝试
开始捕捉
如果null如果(@Error,0)为null
选择@Error=Error\u number(),@Message=Error\u Message();
如果@trancount>0且@XTran=0
回降;
末端捕捉;
返回;
去
有人可能会争辩说,显式发出
set xact_abort off
可能会导致一些不愉快的副作用,例如批终止错误(例如208)跳过
捕获
,并使当前事务保持打开状态。这取决于您;这里的权衡是:

  • 更好的诊断。当数据库中的所有存储过程都遵循此模板时,它们通过输出参数将错误冒泡到最外层的过程,并优雅地回滚所有内容
  • 错误后继续执行的可能性。例如,在事务回滚后记录错误,并确保日志记录不会随事务的其余部分一起消失

接收
的最常见场景。@@tracount=0
需要比您的示例使用的更详细的逻辑

如果在
try
块中调用了其他存储过程,则它们可能对如何管理事务有自己的理解,并且由于编写的代码不好或其他一些问题,它们可能会意外地提交外部事务,或者将其回滚(请记住,任何不引用先前声明的保存点的
rollback
语句都会清除所有内容)。在这种情况下,错误可能会有所不同,可能是导致内部过程首先出现错误,或者如果没有其他错误,您将得到,”执行后的事务计数表示BEGIN和COMMIT语句的数量不匹配。上一个计数=%ld,当前计数=%ld。“

请注意,此行为也可能由触发器执行的回滚引起

当您在
catch
块中没有当前事务时,可能会出现其他一些情况,但显然这些情况非常罕见,我想不出还有什么其他情况

就我个人而言,我尽可能对所有存储过程使用以下模板:

创建过程dbo.ProcTemplate
(
@错误int=null输出,
@消息nvarchar(2048)=空输出
)作为
/*
20191223,RW-待完成
*/
设置nocount、quoted_标识符、ansi_空值、ansi_警告、ansi_填充、concat_空值、arithabort on;
设置xact\u abort、隐式\u事务、数值\u roundabort关闭;
声明@XTran bit=cast(符号(@@tracount)为位);
开始尝试
如果@XTran=0
开始训练;
--把你的代码放在这里
如果@XTran=0
犯罪
结束尝试
开始捕捉
如果null如果(@Error,0)为null
选择@Error=Error\u number(),@Message=Error\u Message();
如果@trancount>0且@XTran=0
回降;
末端捕捉;
返回;
去
有人可能会争辩说,显式发出
set xact_abort off
可能会导致一些不愉快的副作用,例如批终止错误(例如208)跳过
捕获
,并使当前事务保持打开状态。这取决于您;这里的权衡是:

  • 更好的诊断。当数据库中的所有存储过程都遵循此模板时,它们通过输出参数将错误冒泡到最外层的过程,并优雅地回滚所有内容
  • 错误后继续执行的可能性。例如,在事务回滚后记录错误,并确保日志记录不会随事务的其余部分一起消失

一个示例是由
INSERT
调用的触发器,它回滚事务并抛出由
catch
捕获的错误。一个示例是由
INSERT
调用的触发器,它回滚事务并抛出由
catch
捕获的错误。死锁之类的系统错误不会导致这种情况。所以
@@trancount
仍然是
1
,但是