2016-09-28 70 views
1

我有一个Items表&一个Items_Log表,用于记录对Item表的所有更改。TRIGGER中的ROLLBACK导致消息3609

CREATE TABLE [dbo].[Items] (
    [item_id] [int] IDENTITY(1,1) NOT NULL, 
    [item_name] [varchar](50) NOT NULL, 
    [item_desc] [varchar](250) NULL, 
    [modified_by_id] [int] NOT NULL, 
    [modified_date] [datetime] NOT NULL 
) 

CREATE TABLE [dbo].[Items_Log] (
    [item_log_id] [int] IDENTITY(1,1) NOT NULL, 
    [item_id] [int] NOT NULL, 
    [item_name] [varchar](50) NOT NULL, 
    [item_desc] [varchar](250) NULL, 
    [modified_by_id] [int] NOT NULL, 
    [modified_date] [datetime] NOT NULL 
) 

项目表的更新在SPROC中执行。 ([modified_by_id]故意注释,如下面指出的)

CREATE PROCEDURE [dbo].[pUpdateItem] 
    @ItemID INT, 
    @Name VARCHAR(100), 
    @ByID INT 
AS 
    UPDATE [Items] SET 
    item_name = @Name, 
    --modified_by_id = @ByID, 
    modified_date = GETDATE() 
    WHERE item_id = @ItemID; 
GO 

有上时,它以任何方式被更新该记录中的旧数据的项目表的触发器。

ALTER TRIGGER [dbo].[tItemsUpdate] 
    ON [dbo].[Items] 
    AFTER UPDATE 
AS 
BEGIN 
    SET NOCOUNT ON; 

    IF (UPDATE(modified_by_id) AND UPDATE(modified_date)) 
    BEGIN 
     INSERT INTO [Items_Log] 
     SELECT * FROM Deleted 
    END 
    ELSE 
    BEGIN 
     RAISERROR ('[modified_by_id] and [modified_date] must be updated.', 16, 1) 
     ROLLBACK TRANSACTION 
    END 
END 

要测试触发器,[modified_by_id]被注释掉,以便RAISERROR被调用。我得到2错误:

Msg 50000, Level 18, State 1, Procedure tItemsUpdate, Line 15 
[modified_by_id] and [modified_date] must be updated. 
Msg 3609, Level 16, State 1, Procedure pUpdateItem, Line 5 
The transaction ended in the trigger. The batch has been aborted. 

第一个错误显然是我想看到的错误,并且事务正确回滚。但我真的希望它在不抛出第二个错误的情况下退出,因为它会像这样向用户显示。

因此,根据我在其他地方看到的建议,我试着做一个尝试......抓住SPROC,以及正式声明事务和回滚(并将回滚从触发器中取出)。它看起来像这样的存储过程:

BEGIN TRY 
    BEGIN TRANSACTION 
    UPDATE [Items] SET 
     item_name = @Name, 
     --modified_by_id = @ByID, 
     modified_date = GETDATE() 
    WHERE item_id = @ItemID; 
    COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 
    ROLLBACK TRANSACTION 
END CATCH 

现在更新不会发生,但我没有得到任何错误信息都没有。甚至不是来自RAISERROR的人。

我希望我可以简单地压制“Msg 3609”。这将使所有事情都以我想要的方式工作。但在这一点上,我会采取几乎任何有效的解决方案。

任何人都可以帮助我吗?

回答

0
BEGIN CATCH 
    SELECT 
     ERROR_NUMBER() AS ErrorNumber 
     ,ERROR_SEVERITY() AS ErrorSeverity 
     ,ERROR_STATE() AS ErrorState 
     ,ERROR_PROCEDURE() AS ErrorProcedure 
     ,ERROR_LINE() AS ErrorLine 
     ,ERROR_MESSAGE() AS ErrorMessage; 
    ROLLBACK TRANSACTION; 
END CATCH; 

https://msdn.microsoft.com/en-us/library/ms190358.aspx

BEGIN CATCH 
    DECLARE @ErrorSeverity INT, @ErrorState INT, @ErrorMessage VARCHAR(100); 
    SELECT @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(), @ErrorMessage = ERROR_MESSAGE(); 
    ROLLBACK TRANSACTION; 
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState); 
END CATCH 
+0

好吧,我得到了错误的信息这种方式,但现在它不是引发错误回到我的课。我想我可以用捕获的值再次做RAISERROR? – Bob

+0

是的,你可能会提出新的错误,可能会添加一些信息。 – Serg

+0

是的,这将是一个庞大的一点,如果我有在做几乎所有的存储过程,但是这基本上是我现在有: BEGIN CATCH DECLARE @ErrorSeverity INT' 'DECLARE @ErrorState INT' ' DECLARE @ErrorMessage VARCHAR(100)' SET @ErrorSeverity = ERROR_SEVERITY() SET @ErrorState = ERROR_STATE() SET @ErrorMessage = ERROR_MESSAGE() 回滚事务; RAISERROR(@ErrorMessage,@ErrorSeverity,@ErrorState); END CATCH' – Bob

相关问题