你還沒有提到你的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
states的文檔將嚴重性級別小於零的操作解釋爲零,並且嚴重性級別爲states的文檔在嚴重性爲零時不會引發系統錯誤。
事實上,加入RAISERROR
從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;
它顯示爲紅色SSMS中表示「正確」的錯誤。我假設它使用嚴重性16'select * from sys.messages where message_id = 15165'。 RAISERROR'自己提出的錯誤[不**通常會導致'XACT_ABORT'回滾](http://www.sommarskog.se/error-handling-I.html#XACT_ABORT)。不確定系統存儲過程中是否有任何不同。 –