【发布时间】:2017-12-19 15:02:56
【问题描述】:
回滚时出错:
消息 6401,级别 16,状态 1,过程 our_trigger,第 76 行
无法回滚 t1。未找到该名称的事务或保存点。
这是触发器中的 SQL 代码
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [DOCSADM].[our_trigger]
ON [DOCSADM].[PROFILE]
FOR UPDATE, INSERT
AS
DECLARE @DocSystemId AS INTEGER
DECLARE @docNumber AS INTEGER
DECLARE @lastUsedSystemId AS INTEGER
DECLARE @itemType AS VARCHAR(1) --dm10
DECLARE @manualBarcode AS VARCHAR (50)
DECLARE @oldBarcodeFK AS INTEGER
--user typed barcode, it must be inserted/UPDATED into pd_barcode table
DECLARE @COUNTEXISTINGBARCODE AS INTEGER
SET nocount ON;
BEGIN
DECLARE activity_cursor CURSOR local FOR
SELECT
system_id, docnumber,
a_doc_barcode, pd_doc_barcode, item_type
FROM
inserted
--find the last used systemid
SELECT @lastUsedSystemId = lastkey
FROM docsadm.seq_systemkey
OPEN activity_cursor
FETCH next FROM activity_cursor INTO @DocSystemId, @docNumber, @manualBarcode, @oldBarcodeFK, @itemtype
WHILE (@@fetch_status <> -1)
BEGIN
IF (( @itemType = 'M' OR @itemType = 'P' ))
--FIND IF IT EXISTS ALREADY A BARCODE
SELECT @COUNTEXISTINGBARCODE = COUNT(*)
FROM docsadm.pd_barcode
WHERE pd_barcode = @manualBarcode
IF (@COUNTEXISTINGBARCODE = 0)-- THERE IS NO EXISTING BARCODE
DECLARE @barcodeSystemId AS INTEGER = 0
BEGIN TRANSACTION t1
BEGIN TRY
-- get next sys id
EXECUTE [DOCSADM].[Sp_nextkey] 'SYSTEMKEY'
SELECT @barcodeSystemId = lastkey
FROM docsadm.seq_systemkey
INSERT INTO docsadm.pd_barcode
VALUES (@manualBarcode, @barcodeSystemId, 'D', NULL, NULL, 'Y', NULL, NULL)
UPDATE docsadm.profile
SET pd_doc_barcode = @barcodeSystemId
WHERE docnumber = @docNumber
COMMIT TRANSACTION t1
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION t1
END CATCH
END
IF (@COUNTEXISTINGBARCODE <> 0)
--YES THERE IS AT LEAST ONE BARCODE
BEGIN
SELECT TOP 1 @barcodeSystemId = system_id
FROM docsadm.pd_barcode
WHERE pd_barcode = @manualBarcode
BEGIN TRANSACTION t1
BEGIN TRY
--update profile's new barcode reference
UPDATE docsadm.profile
SET pd_doc_barcode = @barcodeSystemId
WHERE docnumber = @docNumber
UPDATE docsadm.pd_barcode
SET pd_doc_bcode_used = 'Y'
WHERE system_id = @barcodeSystemId
IF (@oldBarcodeFK <> 0)
BEGIN
--update old barcode as not used!
UPDATE docsadm.pd_barcode
SET pd_doc_bcode_used = 'N'
WHERE system_id = @oldBarcodeFK
END
COMMIT TRANSACTION t1
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION t1
END CATCH
END
FETCH next FROM activity_cursor INTO @DocSystemId, @docNumber, @manualBarcode, @oldBarcodeFK, @itemtype
END
CLOSE activity_cursor
DEALLOCATE activity_cursor
END
错误来自这里
BEGIN CATCH
ROLLBACK TRANSACTION t1
END CATCH
我试图保存 trans 但我得到了同样的错误。我也在循环之前开始了一个 trans 但消息发生了。
【问题讨论】:
-
天哪! 触发器应该非常灵活和快速 - 它应该最明确不包含游标在性能方面是魔鬼......
-
另外,您已经在事务的上下文中运行(保护导致触发器触发的
UPDATE或INSERT的事务)。你不应该创建“嵌套”事务,如果你想回滚原始的INSERT/UPDATE,你应该只创建ROLLBACK——绝对不是在循环中。 -
是的,这需要完全 100% 重写。嵌套事务是一个神话。他们根本不做看起来应该做的事情。触发器中的事务表明某些事情非常非常错误。从这里看来,这是在游标中完成的唯一真正原因是因为 sp_getNetKey 过程可能需要访问,因为这种类型的密钥生成充满了错误。
-
你说你现在不需要时间来改变它。我想问你什么时候安排时间来解决这个问题,因为它非常需要时间。
-
快速而肮脏的解决方案是摆脱触发器中的所有这些事务。但是你真的需要安排一些时间来解决这个问题,因为它很糟糕。
标签: sql-server triggers transactions