Ros*_*ush 4 trigger sql-server dynamic-sql transaction-log
我不喜欢触发器和动态 sql,但是,我正在使用的东西需要两者。
CREATE TRIGGER [dbo].[GenerateDynamicFormItemViews] ON [dbo].[tblFormItems] AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @DatabaseName NVARCHAR(100)
DECLARE @FormItemID INT
DECLARE db_cursor CURSOR FOR
SELECT SourceID,FormItemID from Inserted
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @DatabaseName, @FormItemID
WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN TRY
EXEC spAddEditFormItemView @FormItemID, @DatabaseName WITH RESULT SETS NONE
END TRY
BEGIN CATCH
INSERT INTO AdminErrorLog(SourceID, ErrorNumber, ErrorState, ErrorSeverity, ErrorProcedure, ErrorLine, ErrorMessage, ErrorDateTime)
SELECT @DatabaseName, ERROR_NUMBER(), ERROR_STATE(), ERROR_SEVERITY(), ERROR_PROCEDURE(), ERROR_LINE(), ERROR_MESSAGE(), GETDATE()
END CATCH
FETCH NEXT FROM db_cursor INTO @DatabaseName, @FormItemID
END
CLOSE db_cursor
DEALLOCATE db_cursor
END
Run Code Online (Sandbox Code Playgroud)
这就是正在发生的事情。
消息:当前事务无法提交,并且无法支持写入日志文件的操作。回滚事务。
严重程度:16
任何人都可以解释为什么 catch 块没有被捕获以及为什么客户端应用程序得到(我的猜测是)sql 异常并回滚所有内容。我的猜测是动态 sql 异常的处理方式不同,并且隐式触发事务正在回滚而不是捕获错误。另外,有谁知道避免传播异常的方法吗?
我敢打赌最安全的解决方案是修改触发器以将 sql 命令填充到表中,然后让 sql 代理作业查找每分钟左右运行的命令。
编辑-添加重新创建的过程:在 SSSM 中:
EXEC [spAddEditFormItemView] 30032,'VP_BENCHMARKING_V05'
Run Code Online (Sandbox Code Playgroud)
命令成功完成。
完成时间:2023-11-27T16:11:18.1762097-05:00
在触发器中,它会强制回滚并显示可怕的错误消息。
ALTER PROCEDURE [dbo].[spAddEditFormItemView] (
@FormItemID int,
@Schema nvarchar(100)
)
AS
DECLARE @SQL NVARCHAR(MAX) = 'e2e2e2e2e'
BEGIN TRY
EXEC (@SQLCommand)
END TRY
BEGIN CATCH
DECLARE @X INT
END CATCH
Run Code Online (Sandbox Code Playgroud)
编辑:我现在可以在 SSMS 中复制。
触发器作为事务的一部分运行。因此,无论 catch 块是否运行,事务都注定会失败,并且永远无法提交到 AdminErrorLog 表。
因此 CATCH 块是否执行并不重要。但事实并非如此,因为触发器范围内的错误通常会中止批处理。请参阅 Erland Sommarskog 关于 TSQL 错误处理的经典文章: https: //www.sommarskog.se/error-handling-I.html#triggercontext