【问题标题】:How to rollback stored procedure that updates a table如何回滚更新表的存储过程
【发布时间】:2020-02-20 13:40:30
【问题描述】:

为什么这个ROLLBACK TRANSACTION 语句不起作用?

BEGIN TRANSACTION;
DECLARE @foo INT
EXECUTE [database].[dbo].[get_counter] @CounterID='inventory_records', @nextValue=@foo OUTPUT;
ROLLBACK TRANSACTION;

背景

我正在将记录插入到基于 SQL Server 19 构建的客户 ERP 系统中。ERP 数据库没有自动递增的主键。它改为使用一个名为counters 的表,其中每一行都有一个counterID 字段和一个整数value 字段。

要在inventory_record 这样的表中插入新行,我首先需要调用这样的存储过程:

EXECUTE get_counter @counterID='inventory_record'

此过程返回一个名为@nextValueOUT 参数,然后我将INSERT 作为其uid 放入inventory_record 表中。

如果我的插入失败,我需要ROLLBACK 这个存储过程的行为。这样,计数器不会在 INSERT 尝试失败时无限增加。

get_counter存储过程的内容

这很简单,但也受版权保护。我在这里进行了总结和截断。计数器作为序列存储在 DB 中。所以get_counter 在检查请求的计数器是否合法后调用sp_sequence_get_range

ALTER PROCEDURE get_counter
    @strCounterID varchar(64),
    @iIncrementValue integer = 1, 
    @LastValue BIGINT = NULL OUTPUT
AS

SET NOCOUNT ON
BEGIN

DECLARE 
          @nextSeqVar SQL_VARIANT
        , @lastSeqVar SQL_VARIANT

-- code that confirms valid counter name

BEGIN TRY
    -- code that calls [sp_sequence_get_range]
END TRY
BEGIN CATCH
    THROW
END CATCH

RETURN(@LastValue)
END

问题

inventory_record 计数器总是递增。我无法回滚。

如果我从 SSMS 运行此问题顶部的 SQL,然后是 SELECT value FROM counters WHERE counterID = 'inventory_record',则每次执行时计数器都会递增。

我是 SQL Server 中事务处理的新手。有什么我想念的想法吗?

【问题讨论】:

  • 为什么不转换为 PK 的 IDENTITY 数据类型? get_counter 中有 COMMIT 吗?
  • get_counter 的代码是什么样的?
  • @MartinSmith 我添加了有关 get_counter 的详细信息。基本上它只是调用一个从序列中获取下一个值的内置系统过程。这两个过程都没有使用任何COMMIT 语句。
  • @alexherm 因为这是一个客户端安装,上面有一个大型 C++ 应用程序,所以我无法更改数据在数据库中的存储方式。
  • 您的insert 语句是否包含在与get_counter 相同的BEGIN TRAN 中?

标签: sql tsql


【解决方案1】:

重新发布 cmets 作为答案以获得更好的可读性。

get_counter 正在使用 Sequence Numbers (sp_sequence_get_range)。请参阅限制部分的documentation

序列号是在当前范围之外生成的 交易。无论交易是否使用 序列号被提交或回滚

您可能会看到一个简单的演示 here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    • 1970-01-01
    • 2016-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多