我有一个系统,需要在数据进入数据库之前为其分配ID。我曾经使用GUID,但发现它们过于庞大,无法证明这种方便性。
现在我正在尝试实现一个序列生成器,它基本上为给定上下文保留了一系列唯一的ID值。代码如下:
ALTER PROCEDURE [dbo].[Sequence.ReserveSequence]
@Name varchar(100),
@Count int,
@FirstValue bigint OUTPUT
AS
BEGIN
SET NOCOUNT ON;
-- Ensure the parameters are valid
IF (@Name IS NULL OR @Count IS NULL OR @Count < 0)
RETURN -1;
-- Reserve the sequence
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION
-- Get the sequence ID, and the last reserved value of the sequence
DECLARE @SequenceID int;
DECLARE @LastValue bigint;
SELECT TOP 1 @SequenceID = [ID], @LastValue = [LastValue]
FROM [dbo].[Sequences]
WHERE [Name] = @Name;
-- Ensure the sequence exists
IF (@SequenceID IS NULL)
BEGIN
-- Create the new sequence
INSERT INTO [dbo].[Sequences] ([Name], [LastValue])
VALUES (@Name, @Count);
-- The first reserved value of a sequence is 1
SET @FirstValue = 1;
END
ELSE
BEGIN
-- Update the sequence
UPDATE [dbo].[Sequences]
SET [LastValue] = @LastValue + @Count
WHERE [ID] = @SequenceID;
-- The sequence start value will be the last previously reserved value + 1
SET @FirstValue = @LastValue + 1;
END
COMMIT TRANSACTION
END
“Sequences”表只包含ID、名称(唯一)和序列的最后一个分配值。使用此过程,我可以请求命名序列中的N个值,并将这些值用作标识符。
到目前为止,这个方法非常好用——它非常快速,因为我不必不断地请求单个值,而是可以使用一系列值,然后再请求更多。
问题在于,在极高的频率下并发调用该过程有时会导致死锁。我发现只有在压力测试时才会出现这种情况,但我担心它会在生产中出现。这个过程中是否存在任何明显的缺陷?有没有人能推荐任何改进方法?例如,不需要事务就可以完成,但我确实需要这个过程是“线程安全”的。
SEQUENCES
。 - marc_s