【问题标题】:SET XACT_ABORT ON Being ignored, transaction continues (SQL Server 2008 R2)SET XACT_ABORT ON 被忽略,事务继续(SQL Server 2008 R2)
【发布时间】:2014-05-01 17:40:47
【问题描述】:

也许我遗漏了一些东西,但即使下面的 RAISERRORs 的严重性为 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'

生产

消息 50000,级别 16,状态 2,过程 RemoveMember,第 20 行
指定用户不是该组的管理员
消息 50000,级别 16,状态 3,过程 RemoveMember,第 24 行
你不能删除自己

我认为XACT_ABORT 应该回滚整个事务,如果它设置为ON

【问题讨论】:

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


    【解决方案1】:

    实际上,它的行为完全符合预期。 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 块。

    【讨论】:

    • 不应该 XACT_ABORT 中止批处理吗?
    • @usr 重新检查:排除显式 RAISERROR 以及其他一些类型的错误。
    • 看起来可能就是这样。我将在调用 RAISERROR 的检查末尾添加 IF @@ERROR 0 并添加额外的 RETURN 语句
    【解决方案2】:

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

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

    开始尝试 -- 插入或抛出错误 -- 提交事务 结束尝试 开始捕捉 -- 回滚 结束捕获;

    【讨论】:

    • 抱歉,忘记说明了,SQL Server 2008 R2 不支持 THROW 语句
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-19
    • 1970-01-01
    相关资源
    最近更新 更多