SET XACT_ABORT ON被忽略,事务继续(SQL Server 2008 R2)

时间:2014-05-01 17:40:47

标签: sql-server tsql sql-server-2008-r2 xact-abort

也许我错过了一些东西,但即使下面RAISERROR的严重性为16(根据文档),交易仍然会被提交,好像XACT_ABORT ON没有效果。

CREATE PROCEDURE [ExploringGroups].[RemoveMember]
@groupId        uniqueidentifier,
@adminUsername  nvarchar(50),
@targetUsername nvarchar(50)
AS
SET XACT_ABORT ON

BEGIN TRANSACTION

DECLARE
    @adminUserId    uniqueidentifier = dbo.fn_userId(@adminUsername),
    @targetUserId   uniqueidentifier = dbo.fn_userId(@targetUsername)

IF @targetUserId IS NULL OR ExploringGroups.IsMember(@groupId, @targetUserId) = 0
    RAISERROR('Target user was not located', 16, 1)

IF ExploringGroups.IsInRole(@groupId, @adminUserId, 'adm') = 0
    RAISERROR('Specified user is not an administrator of this group', 16, 2)

IF @adminUserId = @targetUserId
    RAISERROR('You cannot remove yourself', 16, 3)

    -- statements below still execute and commit even though there was an error raised above
DELETE FROM ExploringGroups.MemberRole WHERE GroupId = @groupId AND UserId = @targetUserId
DELETE FROM ExploringGroups.Membership WHERE GroupId = @groupId AND UserId = @targetUserId

COMMIT

RETURN 0

致电

exec exploringgroups.removemember '356048C5-BAB3-45C9-BE3C-A7227225DFDD', 'Crypton', 'Crypton'

可生产

  

Msg 50000,Level 16,State 2,Procedure RemoveMember,Line 20
  指定用户不是该组的管理员
  Msg 50000,Level 16,State 3,Procedure RemoveMember,Line 24
  你不能自己删除

我认为XACT_ABORT如果设置为ON,应该回滚整个交易吗?

2 个答案:

答案 0 :(得分:2)

实际上,它的行为完全符合预期。 XACT_ABORT确实导致事务回滚,所以是否有任何数据修改直到错误点将被回滚。但是,它不会影响执行流程,并且它不会停止运行存储过程,因此以下两个DELETE作为隐含事务执行。明确的RAISERROR不会中止批次。

请参阅此简化版本:

create table #t(i int);
insert #t values(1);
go

alter procedure sp
as
set xact_abort on
begin tran
raiserror ('x', 16, 1);
print 'deleting';
delete #t;
commit;
go

exec sp
go

select * from #t
go

唯一有趣的是,有关COMMIT没有相应BEGIN TRAN的错误被吞下。

使用SEH,它会跳转到CATCH块。

答案 1 :(得分:1)

你应该使用“THROW”语句而不是RAISERROR方法。

使用BEGIN TRY和BEGIN CATCH并正常提交事务或在CATCH块中回滚。

开始尝试   - 插入或抛出错误   - 提交交易 结束 开始捕捉   - 回滚 END CATCH;