也许我错过了一些东西,但即使下面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
,应该回滚整个交易吗?
答案 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;