gpt4 book ai didi

sql - 在事务中更新表(使用 Service Broker 的审计触发器)

转载 作者:行者123 更新时间:2023-12-04 17:19:12 24 4
gpt4 key购买 nike

我们已经使用服务代理实现了审计功能,并在需要审计的表上实现了触发器。我们面临的问题是当我们尝试从事务中更新可审计表时,它会抛出错误 -

The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.

但是,如果我们从可审核表中删除触发器,一切都会正常进行。不可能在事务中更新表(带触发器),还是我们在最后遗漏了什么?

更新交易

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)作为开始 开始尝试 声明@dlgId UNIQUEIDENTIFIER,@dlgIdExists BIT 选择@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

结束

最佳答案

在发出 ROLLBACK TRANSACTION 之后,您仍然可以访问 ERROR_PROCEDURE() 等函数,这是您需要在 CATCH block 中执行的操作。查看 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;

至于潜在的错误是什么(目前在您的错误报告中出错),如果我不得不猜测那将是您的消息的契约(Contract)无法处理 XML 中出现的多行数据。但我们需要查看契约(Contract)以确认这一点。

关于sql - 在事务中更新表(使用 Service Broker 的审计触发器),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5229831/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com