我不喜欢触发器和动态 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
这就是正在发生的事情。
- AWS DMS 复制任务正在批量复制 10,000 个数据。复制的实现是一个黑匣子,但连接上似乎存在嵌套事务。
- EXEC spAddEditFormItemView 调用一个存储过程,该存储过程执行动态 sql 并在一条记录上出错。
- CATCH 块永远不会被执行
- 该错误永远不会进入 AdminErrorLog。
- AWS Batch 出错并且从未提交,整个任务失败。
- 在扩展事件中,捕获以下 SQL 错误。这是导致任务失败的错误。我读到了有关命令既不能处于提交或回滚状态的情况,但确实没有完全理解这个概念。
消息:当前事务无法提交,并且无法支持写入日志文件的操作。回滚事务。
严重程度:16
任何人都可以解释为什么 catch 块没有被捕获以及为什么客户端应用程序得到(我的猜测是)sql 异常并回滚所有内容。我的猜测是动态 sql 异常的处理方式不同,并且隐式触发事务正在回滚而不是捕获错误。另外,有谁知道避免传播异常的方法吗?
我敢打赌最安全的解决方案是修改触发器以将 sql 命令填充到表中,然后让 sql 代理作业查找每分钟左右运行的命令。
编辑-添加重新创建的过程:在 SSSM 中:
EXEC [spAddEditFormItemView] 30032,'VP_BENCHMARKING_V05'
命令成功完成。
完成时间: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
编辑:我现在可以在 SSMS 中复制。
触发器作为事务的一部分运行。因此,无论 catch 块是否运行,事务都注定会失败,并且永远无法提交到 AdminErrorLog 表。
因此 CATCH 块是否执行并不重要。但事实并非如此,因为触发器范围内的错误通常会中止批处理。请参阅 Erland Sommarskog 关于 TSQL 错误处理的经典文章: https: //www.sommarskog.se/error-handling-I.html#triggercontext