我们已经使用服务代理实现了审计功能,并在需要审计的表上实现了触发器。我们面临的问题是当我们尝试从事务中更新可审计表时,它会引发错误 -
目前的交易不可能 承诺,不能支持 写入日志文件的操作。 回滚交易。
但是,如果我们从可审核表中删除触发器,则一切正常。是不是可以在交易中更新表(带触发器),还是我们在最后遗漏了什么?
更新交易
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 ) 如 开始 开始尝试 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
END
答案 0 :(得分:1)
在您的CATCH块中发布ERROR_PROCEDURE()
后,您仍然可以访问ROLLBACK TRANSACTION
等功能,这是您需要执行的操作。查看Using TRY...CATCH in 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中出现的多行数据。但我们需要看到合同来确认这一点。
答案 1 :(得分:1)
我有同样的错误,因为我使用了相同的例子:service broker audit
我终于设法收到此消息的错误,这是安全问题。您有独立的审计记录数据库。您的procAuditSendData在update / insert / delete命令的上下文中执行(它使用相同的凭据)。就我而言,procAuditSendData上下文的用户无权访问审计数据库。为了修复错误,您必须在单独的审计数据库中添加该上下文用户,并授予他datareader和datawriter的权限。我这样做了,之后一切都像魅力一样。