0

SETXACT_ABORTONを使用した2つの類似したTSQLスクリプトがあります。エラーを発生させるトランザクションにラップされたステートメントを意図的に使用しているため、スクリプトの実行後に _testテーブルが存在しないことを期待しています。

最初のスクリプトは、_testテーブルの作成を正しくロールバックします。

SET XACT_ABORT ON
GO
BEGIN TRANSACTION
CREATE TABLE dbo._test(ID int IDENTITY(1, 1) NOT NULL)
EXEC sp_does_not_exist --raises error!
GO
IF @@TRANCOUNT > 0
    COMMIT;

ただし、2番目のスクリプトは_testの作成をロールバックせず、テーブルはスクリプトの実行後に存在します。

SET XACT_ABORT ON
GO
BEGIN TRANSACTION
CREATE TABLE dbo._test(ID int IDENTITY(1, 1) NOT NULL)
EXEC sp_recompile sp_does_not_exist; --raises error!
GO
IF @@TRANCOUNT > 0
    COMMIT;

2番目のスクリプトが実行後に_testテーブルを削除しないのはなぜですか?

4

1 に答える 1

0

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

実際、RAISERRORfromsp_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、データベースエンジンによって「直接」エラーが発生したため、2番目は実行されません。

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;
于 2012-11-30T21:34:47.533 に答える