为什么在存储过程中使用 sp_addextendedproperty 时需要回滚?

ber*_*d_k 5 sql-server transaction

此处输入链接描述中,我展示了我如何记录数据库。

为了插入扩展属性,最初我使用 sp_addextendedproperty 调用的计划序列。

但是最近,当我在旧版本的数据库上运行脚本时,我想捕获有关不存在对象的错误。

我通过反复试验找到了以下工作代码

begin try 
drop procedure dbo.BK_add_Tableproperty
end try begin catch end catch

go
create procedure dbo.BK_add_Tableproperty (
    @table_name sysname,
    @property_name nvarchar(max),
    @Property_value sysname
)
as  
    declare @error integer;
begin try
    EXEC sys.sp_addextendedproperty @name= @property_name,
    @value = @Property_value, 
    @level0type=N'SCHEMA',
    @level0name=N'dbo', 
    @level1type=N'TABLE',
    @level1name=@table_name
end try begin catch
    SET @error = @@ERROR;
    if @error = 15135
        Print 'Table missing no extended properties added: ' + @table_name
    else if @error = 15233
        Print 'Table has already property: ' + @table_name + ' - ' + @property_name
    else
        Print 'unexpected error ' + str(@error)          
    ROLLBACK;  
end catch

go
Run Code Online (Sandbox Code Playgroud)

让我感到困惑的是,我必须在捕获路径中添加 ROLLBACK。在msdn我没有发现任何提示,即 sp_addextendedproperty 使用事务。谁能解释一下?

对 gbn 的回答:

返回无条件退出程序。我在每个路径中只看到 1 个提交:

BEGIN TRANSACTION

begin
    EXEC %%ExtendedPropertySet().AddValue(Name = @name, Value = @value, Level0type = @level0type, Level0name = @level0name, Level1type = @level1type, Level1name = @level1name, Level2type = @level2type, Level2name = @level2name)
    IF @@error <> 0
    begin
        COMMIT TRANSACTION
        return (1)
    end
end

COMMIT TRANSACTION
return (0)
Run Code Online (Sandbox Code Playgroud)

向 Microsoft 连接报告为错误:

https://connect.microsoft.com/SQLServer/feedback/details/658556/sp-addextendedproperty-leaves-on-open-transaction-when-an-error-occured

改进版本(更好的错误处理和固定的参数类型。 (原始问题不受影响,但是这会在错误消息中处理 NLS)

create procedure dbo.BK_add_Columnproperty (
    @table_name sysname,
    @Column_name sysname,
    @property_name nvarchar(max),
    @Property_value sql_variant
)
as  
begin try
    --SET XACT_ABORT ON
    EXEC sys.sp_addextendedproperty @name= @property_name,
    @value = @Property_value, 
    @level0type=N'SCHEMA',
    @level0name=N'dbo', 
    @level1type=N'TABLE',
    @level1name=@table_name,
    @level2type=N'COLUMN',
    @level2name=@Column_name
end try begin catch
    -- SELECT XACT_STATE()    -- returns 1 or -1 when SET XACT_ABORT ON 
    if ERROR_NUMBER() = 15135 -- object invalid
        print '      ' + str(ERROR_NUMBER()) + ' -- ' + ERROR_MESSAGE() 
    else
        print '##### ' + str(ERROR_NUMBER()) + ' -- ' + ERROR_MESSAGE() 
    ROLLBACK;  
end catch

go
Run Code Online (Sandbox Code Playgroud)

gbn*_*gbn 3

这条线..

SELECT OBJECT_DEFINITION(OBJECT_ID('sp_addextendedproperty'))
Run Code Online (Sandbox Code Playgroud)

...显示 sp_addextendedproperty 有 2 x COMMIT。如果事务可以提交(即不是“注定”),那么这不会成为问题,但否则会使事务保持打开状态。

这很可能是MS Connect上报告的错误

像这样的 catch 块将显示交易是否注定失败

begin catch

SELECT XACT_STATE() -- -1 = doomed, 0 = none, 1 = commit or rollback

    SET @error = ERROR_NUMBER();

    if @error = 15135
        Print 'Table missing no extended properties added: ' + @table_name;
    else if @error = 15233
        Print 'Table has already property: ' + @table_name + ' - ' + @property_name;
    else
        Print 'unexpected error ' + str(@error); 

end catch
Run Code Online (Sandbox Code Playgroud)

我还没有在工作中见过这个(开放的 txn)(仍然是 SQL Server 2005 SP3),并且从 VM 上的本地 SQL Server 2008 获取了详细信息。可能与版本有关。

编辑:刚刚看到Q更新

使用 SET XACT_ABORT ON 无论如何都会强制回滚