我正在使用 ASP.NET Core Minimal API (.NET 7) 和 Entity Framework Core、HotChocolate(用于 GraphQL)和 Microsoft SQL Server 数据库开发 API 后端。我遇到了有关数据突变的具体挑战,希望得到任何指导或建议。
在我的应用程序中,用户可以针对特定突变的每个请求提交多个输入(出于演示目的,我们仅使用 1-10 之间的数字)。然后,这些输入被分组为子组(例如,1-4、5-8、9-10,创建组的原因和方式对于这个问题并不重要。)。每个子组都分配有一个唯一的全局标识符。这些标识符遵循特定的格式,例如 GROUP-XXX-1、GROUP-XXX-2 等,其中数字部分(例如 1、2)需要是其他组在该组中未使用过的最低可用数字。数据库。
我努力设计一种高效可靠的方法来为每个请求保留和分配这些唯一的连续编号。关键要求是:
每个数字在所有组中都必须是唯一的。 分配的编号应该是序列中最小的可用编号。
问题:
如何实现一个系统来保留和分配这些唯一的连续编号,以确保唯一性并最大限度地减少序列中的间隙? 是否有任何最佳实践或模式可以简化此任务? 任何见解、代码片段或相关文档的引用将不胜感激。
我感谢您提供的任何帮助。
您可以使用组标识符“GROUP-XXX”作为主键(或唯一键列)来实现高水位线表,并将最后分配的序列号存储为第二列。存储过程可用于自动分配新的序列号。
限制:不支持释放和重用。
类似:
CREATE TABLE GroupSequence (
GroupKey VARCHAR(100) NOT NULL
CONSTRAINT PK_GroupSequence PRIMARY KEY,
LastSequenceNumber INT NOT NULL
)
CREATE PROCEDURE AllocateGroupSequence
@GroupKey VARCHAR(100),
@AssignedSequenceNumber INT OUTPUT
AS
-- Create row is not already present (first time only)
INSERT INTO GroupSequence (GroupKey, LastSequence)
VALUES (@GroupKey, 0)
WHERE NOT EXISTS(
SELECT *
FROM GroupSequence
WHERE GroupKey = @GroupKey
)
DECLARE @OutputCapture TABLE (
AssignedSequenceNumber INT NOT NULL
)
-- Assign sequence by incrementing counter and capturing the updated value
UPDATE GroupSequence
SET LastSequence = LastSequence + 1
OUTPUT INSERTED.LastSequenceNumber INTO @Capture
WHERE GroupKey = @GroupKey
-- Copy the captured value to the output parameter
SELECT @AssignedSequenceNumber = AssignedSequenceNumber
FROM @OutputCapture
第一个语句处理新的
GroupKey
值并引导新行。它仅在第一次请求时插入任何给定的 GroupKey
值。第二个语句同时增加 LastSequenceNumber
列并捕获本地表变量中的更新值。重要的是,使用 OUTPUT
子句来捕获递增值的同一语句中的更新值。
存储过程中的两条语句将以原子方式操作,即在两个同时操作的情况下,最多一个会插入,并且由于正常的 SQL Server 锁定行为,分配和更新将相继发生。
重要提示:如果在事务中执行分配,则该行将保持锁定状态,直到事务提交(或回滚)。如果两个不同的处理每次尝试分配两个或多个具有不同 GroupKey 值但顺序不同的序列号,则可能会发生死锁。如果将应用程序逻辑编写为始终按明确定义的顺序分配多个序列号(例如按升序 GroupKey 排序),则可以避免这种情况。
*这是我未经测试的。如果有人看到我的逻辑错误,请评论,我会纠正。