1

我在一个数据库中有一个表,它引用了另一个数据库中表的 ID。我已经设置了代替插入/更新触发器,以防止插入另一个表中不存在的 ID。我希望这些触发器在发现不存在的 ID 时中止事务,否则继续事务。

这是我尝试过的:

CREATE TRIGGER [dbo].[tr_check_student_insert]
    ON [dbo].[student]
    INSTEAD OF INSERT
AS
BEGIN
    SET XACT_ABORT ON

    IF (EXISTS ... )
    BEGIN
        RAISERROR (N'[teacher_id] does not exist in [teacher]',11,1)
    END

    IF (EXISTS ... )
    BEGIN
        RAISERROR (N'[class_id] does not exist in [class]',11,1)
    END

    INSERT INTO [dbo].[student] ...
END

此后我发现 RAISERROR 不会中止事务,即使 SET XACT_ABORT ON,并且在引发错误后仍会发生插入(或更新)。

我知道我可以将每个条件包装在 IF/ELSE IF 语句中,并在 ELSE 上调用插入,但我只是想知道是否有一种方法可以立即退出并回滚整个事务。

4

1 回答 1

1

你需要在BEGIN TRANSACTION一个ROLLBACKTRY CATCH

尝试这样的事情:

CREATE TRIGGER [dbo].[tr_check_student_insert]
    ON [dbo].[student]
    INSTEAD OF INSERT
AS
BEGIN
BEGIN TRY
BEGIN TRANSACTION
SET NOCOUNT ON;

    IF (EXISTS ... )
    BEGIN
        RAISERROR (N'[teacher_id] does not exist in [teacher]',11,1)
    END

    IF (EXISTS ... )
    BEGIN
        RAISERROR (N'[class_id] does not exist in [class]',11,1)
    END

    INSERT INTO [dbo].[student] ...

;
COMMIT
END TRY

BEGIN CATCH

IF @@TRANCOUNT > 0
     ROLLBACK

    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;
       RETURN;
END CATCH

END
于 2015-03-04T17:09:27.307 回答