您没有提到您的 SQL Server 版本,但由于您的脚本的唯一区别是sp_recompile
,这似乎是一个很好的查看位置。在 2008R2 中,它具有以下逻辑:
BEGIN TRANSACTION
-- CHECK VALIDITY OF OBJECT NAME --
-- (1) Must exist in current database
-- (2) Must be a table or an executable object
select @objid = object_id(@objname, 'local')
if @objid is null OR
(ObjectProperty(@objid, 'IsTable') = 0 AND
ObjectProperty(@objid, 'IsExecuted') = 0)
begin
COMMIT TRANSACTION
raiserror(15165,-1,-1 ,@objname)
return @@error
end
因此,在尝试直接访问对象之前sp_recompile
检查对象是否存在,如果未找到,则会引发严重性为 -1 的错误。文档说明严重性级别小于零被解释为零,严重性级别文档说明严重性为零时不会引发系统错误。RAISERROR
实际上,将RAISERROR
from添加sp_recompile
到您的脚本中表明它不会影响@@TRANCOUNT
:
SET XACT_ABORT ON
GO
BEGIN TRANSACTION
CREATE TABLE dbo._test(ID int IDENTITY(1, 1) NOT NULL)
select @@trancount as 'before raiserror'
raiserror(15165,-1,-1 ,'sp_does_not_exist')
select @@trancount as 'after raiserror'
GO
IF @@TRANCOUNT > 0
COMMIT;
@@TRANCOUNT
在引发错误之前和之后为 1,因此没有什么可以触发回滚。但是如果你这样做,第二个SELECT
永远不会执行,因为数据库引擎“直接”引发了错误:
SET XACT_ABORT ON
GO
BEGIN TRANSACTION
CREATE TABLE dbo._test(ID int IDENTITY(1, 1) NOT NULL)
select @@trancount as 'before raiserror'
exec sp_does_not_exist
select @@trancount as 'after raiserror'
GO
IF @@TRANCOUNT > 0
COMMIT;