Sql server 在事务的捕获范围内,@trancount怎么可能为零?
我有一个带有事务和try/catch的语句块: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; 我在这里使用的是
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
,但是