在TRIGGER中的ROLLBACK导致Msg 3609

时间:2016-09-28 19:55:11

标签: sql sql-server triggers transactions rollback

我有一个项目表&一个Items_Log表,用于记录对Item表的所有更改。

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
)

Items表的更新在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

Items表上有一个Trigger,它以任何方式更新旧数据。

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中进行Try ... Catch,以及在那里进行事务和回滚的正式声明(以及将Trigback从Trigger中取出)。它在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”。这将使一切按照我想要的方式工作。但在这一点上,我几乎可以采取任何有效的解决方案。

任何人都可以帮我吗?

1 个答案:

答案 0 :(得分: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