サービスブローカーを使用して監査機能を実装し、監査が必要なテーブルにトリガーを実装しました。私たちが直面している問題は、トランザクション内から監査可能なテーブルを更新しようとすると、エラーが発生することです-
現在のトランザクションはコミットできず、ログファイルに書き込む操作をサポートできません。トランザクションをロールバックします。
ただし、監査可能テーブルからトリガーを削除すると、すべて正常に機能します。トランザクション内でテーブル(トリガー付き)を更新することはできませんか、それとも最後に何かが不足していますか?
トランザクションの更新
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
終わり