3

サービスブローカーを使用して監査機能を実装し、監査が必要なテーブルにトリガーを実装しました。私たちが直面している問題は、トランザクション内から監査可能なテーブルを更新しようとすると、エラーが発生することです-

現在のトランザクションはコミットできず、ログファイルに書き込む操作をサポートできません。トランザクションをロールバックします。

ただし、監査可能テーブルからトリガーを削除すると、すべて正常に機能します。トランザクション内でテーブル(トリガー付き)を更新することはできませんか、それとも最後に何かが不足していますか?

トランザクションの更新

BEGIN TRAN
    update  ActivationKey set OrderLineTransactionId = @orderLineTransactionId, LastUpdated = getUtcdate(), [Status] =2  
    where   PurchaseTransactionId = @transactionid 
        -- Rollback the transaction if there were any errors
            IF @@ERROR <> 0 
                ROLLBACK
            ELSE        
                COMMIT TRAN
END TRAN                

引き金

ALTER TRIGGER [dbo].[ActivationKey_AuditTrigger]
     ON  [dbo].[ActivationKey]
    AFTER INSERT, UPDATE, DELETE 
    AS
    BEGIN
        SET NOCOUNT ON;

        DECLARE @auditBody XML
        Declare @newData nvarchar(MAX)
        DECLARE @DMLType CHAR(1)    
        -- after delete statement
        IF NOT EXISTS (SELECT * FROM inserted)
        BEGIN   
            SELECT  @auditBody = (select * FROM deleted AS t FOR XML AUTO, ELEMENTS),
                    @DMLType = 'D'
        END 
        -- after update or insert statement
        ELSE
        BEGIN
                --after Update Statement
            IF EXISTS (SELECT * FROM deleted)
              begin
                    SELECT      @auditBody = (select * FROM deleted AS t FOR XML AUTO, ELEMENTS)
                    SELECT      @newData = (select * FROM Inserted AS t FOR XML AUTO, ELEMENTS)
                    SELECT      @DMLType = 'U'
              end
              ELSE -- after insert statement
              begin
                    SELECT      @auditBody = (select * FROM inserted AS t FOR XML AUTO, ELEMENTS)
                    SELECT      @DMLType = 'I'
              end
        END

        -- get table name dynamicaly but
        DECLARE @tableName sysname 
        SELECT  @tableName = 'ActivationKey'

        SELECT @auditBody = 
            '<AuditMsg>
                <SourceDb>' + DB_NAME() + '</SourceDb>
                <SourceTable>' + @tableName + '</SourceTable>
                <UserId>' + SUSER_SNAME() + '</UserId>
                <DMLType>' + @DMLType + '</DMLType>
                <ChangedData>' + CAST(@auditBody AS NVARCHAR(MAX)) + '</ChangedData>
                <NewData>' + isnull(@newData,'') + '</NewData>
            </AuditMsg>'
        -- Audit data asynchrounously
        EXEC dbo.procAuditSendData @auditBody
    END 

トリガー内から呼び出されたストアドプロシージャ(procAuditSendData)

ALTER PROCEDURE [dbo].[procAuditSendData]

(@AuditedData XML)AS BEGIN BEGIN TRY DECLARE @dlgId UNIQUEIDENTIFIER、@ dlgIdExists BIT SELECT @dlgIdExists = 1

    SELECT  @dlgId = DialogId
    FROM    vwAuditDialogs AD 
    WHERE   AD.DbId = DB_ID()
    IF  @dlgId IS NULL
    BEGIN 
        SELECT @dlgIdExists = 0
    END

    -- Begin the dialog, either with existing or new Id
    BEGIN DIALOG @dlgId
        FROM SERVICE    [//Audit/DataSender]                                               
        TO SERVICE      '//Audit/DataWriter', 
                'BAAEA6F1-C97E-4884-8651-2829A2049C46'
        ON CONTRACT     [//Audit/Contract]
    WITH ENCRYPTION = OFF;

    -- add our db's dialog to AuditDialogs table if it doesn't exist yet
    IF @dlgIdExists = 0
    BEGIN 
        INSERT INTO vwAuditDialogs(DbId, DialogId)
        SELECT  DB_ID(), @dlgId
    END
    --SELECT @AuditedData

    -- Send our data to be audited
    ;SEND ON CONVERSATION @dlgId    
    MESSAGE TYPE [//Audit/Message] (@AuditedData)
END TRY
BEGIN CATCH
    INSERT INTO AuditErrors (
            ErrorProcedure, ErrorLine, ErrorNumber, ErrorMessage, 
            ErrorSeverity, ErrorState, AuditedData)
    SELECT  ERROR_PROCEDURE(), ERROR_LINE(), ERROR_NUMBER(), ERROR_MESSAGE(), 
            ERROR_SEVERITY(), ERROR_STATE(), @AuditedData
END CATCH

終わり

4

2 に答える 2

1

CATCHブロックで、ここで行う必要があることERROR_PROCEDURE()を発行した後でも、etc関数にアクセスできます。TransactSQLでのTRY...CATCHROLLBACK TRANSACTIONの使用の例、特に「エラー処理の例」のコードを見てください。エラーをログに記録するために呼び出すプロシージャ()は、その上にいくつかのサンプルが表示されます。uspLogError

BEGIN CATCH
    -- Call procedure to print error information.
    EXECUTE dbo.uspPrintError;

    -- Roll back any active or uncommittable transactions before
    -- inserting information in the ErrorLog.
    IF XACT_STATE() <> 0
    BEGIN
        ROLLBACK TRANSACTION;
    END

    EXECUTE dbo.uspLogError @ErrorLogID = @ErrorLogID OUTPUT;
END CATCH; 

根本的なエラー(現在、エラーレポートでエラーが発生しています)については、メッセージのコントラクトがXMLに表示される複数行のデータに対応できないと推測する必要があります。しかし、それを確認するために契約を確認する必要があります。

于 2011-03-08T11:49:46.583 に答える
1

あなたが行ったのと同じ例を使用したので、同じエラーが発生しました:サービスブローカー監査

私はついにこのメッセージのエラーを得ることができました、そしてそれはセキュリティの問題でした。監査レコード用に個別のデータベースがあります。procAuditSendDataは、update / insert / deleteコマンドのコンテキストで実行されます(同じ資格情報を使用します)。私の場合、procAuditSendDataコンテキストのユーザーには、監査データベースにアクセスする権限がありませんでした。エラーを修正するには、そのコンテキストユーザーを別の監査データベースに追加し、データリーダーとデータライターの権限を付与する必要があります。私はこれを行い、その後すべてが魅力のように機能しました。

于 2013-02-12T10:17:50.530 に答える