序列和身份提供全球独一无二的递增值在所有会话和事务,无论隔离级别,他们不受事务回滚的影响。 有可能得到相同的行为和基于行的柜台,如果是这样,如何可以做到吗?
最大的问题似乎是执行柜台更新任何事务的范围之外,可能是开放的。 服务器链接可以自己调用自己的程序的“远程模式”拳通过任何当前活动事务隔离模式?
“远程”调用就可以这样调用一个简单的过程运行在自动提交模式:
create or alter procedure dbo.next_value (@id int, @result int = null output) as begin set nocount on; update dbo.RowBasedCounters set @result = counter_value = counter_value + 1 where counter_id = @id; return @result; end; 背景:我们需要完全相同的行为序列或身份的文件/传输计数器外部通信合作伙伴,对对方的三个独立的柜台。 然而,使用序列或身份并不可行,因为这些需要一个单独的数据库对象命名为每个计数器(即单例对象而不是键控),和在任何情况下有成千上万的伙伴,因此许多千计数器。
注: :这些计数器数字传输(EDI文件)和传输尝试沟通合作伙伴之间在德国医疗系统; 文件为每一对合作伙伴编号从1开始,每年转移尝试永远模编号1000,还为每一对合作伙伴。数字必须是连续的。编号方案由我们控制之外的标准和定义的。
我们使用MS SQL Server 2014。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
在您的场景中,您希望实现一个类似序列或身份列的递增计数器功能,但需要避免为每个合作伙伴创建单独的数据库对象,并且这个计数器需要在事务回滚时保持递增值不变。基于您的描述和给出的代码示例,这里是一个可能的解决方案:
您已经提供了一个存储过程示例,该过程通过更新一个包含所有计数器的表(dbo.RowBasedCounters
)来递增计数器值。这种方法是可行的,因为它允许你针对特定的counter_id
进行操作,而不需要为每个计数器创建独立的对象。
为了确保事务隔离性和递增的原子性,可以利用SQL Server的乐观锁或悲观锁机制。在您的例子中,通过立即更新并返回新值的方式实际上已经隐式地使用了悲观锁(通过更新语句锁定行)。但是,为了更明确地控制并发访问,可以显式地使用WITH (UPDLOCK)
提示来锁定行,防止其他会话在同一时间修改同一计数器。
修改后的存储过程示例:
CREATE OR ALTER PROCEDURE dbo.Next_Value (@id INT, @result INT = NULL OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
-- 显式加锁以防止并发更新冲突
UPDATE dbo.RowBasedCounters WITH (UPDLOCK)
SET @result = counter_value = counter_value + 1
WHERE counter_id = @id;
-- 如果没有找到对应的counter_id,则可以考虑插入新行或者抛出错误
IF (@@ROWCOUNT = 0)
BEGIN
RAISERROR('Counter with specified ID not found', 16, 1);
RETURN;
END
RETURN @result;
END;
您提到需要在事务范围之外执行计数器更新,以确保其不受事务回滚影响。由于您已经在存储过程中直接执行更新操作,这通常意味着每次调用都会即时提交更改,除非它被外部事务包围。因此,只要直接调用此存储过程,而不将其嵌入到另一个事务中,就能达到目的。
对于“远程模式”调用,确保连接到数据库时使用的应用程序配置为自动提交事务(这是大多数数据库连接的默认行为),这样每次调用存储过程都会立即提交,不会受到外部事务的影响。
通过上述方法,您可以实现一个全局唯一的、递增的计数器系统,该系统不受事务回滚的影响,并且可以在不为每个合作伙伴创建单独数据库对象的情况下工作。请确保在部署和测试时充分考虑并发访问的处理,以及如何处理计数器初始化或未找到的情况。