Обновление таблицы (с помощью триггера аудита с использованием Service Broker) в транзакции - PullRequest
3 голосов
/ 08 марта 2011

Мы внедрили возможность аудита с использованием сервисного брокера и внедрили триггеры для таблиц, которые необходимо проверять.Проблема, с которой мы сталкиваемся, заключается в том, что когда мы пытаемся обновить контролируемую таблицу из транзакции, она выдает ошибку -

Текущая транзакция не может быть зафиксирована и не может поддерживать операции записи в файл журнала.,Откат транзакции.

Однако, если мы удалим триггер из проверяемой таблицы, все будет работать абсолютно нормально.не возможно ли обновить таблицу (с триггером) внутри транзакции или мы что-то упустили в конце?

Обновление транзакции

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 

Сохраненный Proc (procAuditSendData) вызывается из триггера

ALTER PROCEDURE [dbo].[procAuditSendData]

(@AuditedData XML), КАК НАЧИНАЕТСЯ ПОПРОБОВАТЬ @DlgId UNIQUEIDENTIFIER, @dlgIdExists BIT SELECT @dlgIdExists * 1 * * * 99 * 1 1

END

Ответы [ 2 ]

1 голос
/ 12 февраля 2013

У меня была такая же ошибка, поскольку я использовал тот же пример, что и вы: аудит сервисного брокера

Мне наконец удалось получить сообщение об ошибке, и это был вопрос безопасности. У вас есть отдельная база данных для записей аудита. Ваш procAuditSendData выполняется в контексте вашей команды update / insert / delete (он использует те же учетные данные). В моем случае пользователь из контекста procAuditSendData не имел прав доступа к базе данных аудита. Чтобы исправить вашу ошибку, вы должны добавить этого контекстного пользователя в вашу отдельную базу данных аудита и предоставить ему права чтения данных и записи данных. Я сделал это, и после этого все заработало как шарм.

1 голос
/ 08 марта 2011

Вы по-прежнему можете получить доступ к функциям ERROR_PROCEDURE() и т. Д. После того, как вы ввели ROLLBACK TRANSACTION, что вам нужно сделать здесь, в вашем блоке CATCH.Посмотрите на примеры в Использование TRY ... CATCH в Transact SQL , особенно посмотрите на код в «примере обработки ошибок».Процедура, которую она вызывает для регистрации ошибок (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.Но нам нужно увидеть контракт, чтобы подтвердить это.

...