在数据库中创建 JVM 级别和线程安全序列

Creating JVM level and Thread Safe Sequence in DB

这是个老问题了,但为了确定我又问了一遍。 实际上,我已经像在 Oracle 中一样使用 table 创建了序列,并希望与多个线程一起使用,并且多个 JVM 的所有进程都将并行运行。

以下是序列存储过程,只是想问一下这是否适用于多个 JVM,并且始终为所有 jvm 中的线程提供唯一编号,或者它是否有可能在两次以上的调用中返回相同的序列号?

create table sequenceTable (id int)
insert into sequenceTable values (0)

create procedure mySequence 
AS
BEGIN
    declare @seqNum int
    declare @rowCount int

    select @rowCount = 0
    while(@rowCount = 0)
    begin
        select @seqNum = id from sequenceTable
        update sequenceTable set id = id + 1 where id = @seqNum
        select @rowCount = @@rowcount
        print 'numbers of rows update %1!', @rowCount
    end
    SELECT @seqNum
END

您可以在 ASE 中模拟序列。使用 reserve_identity 函数实现所需类型 activity:

create table sequenceTable (id bigint identity)
go

create procedure mySequence AS
begin
    select reserve_identity('sequenceTable', 1)
end
go

此解决方案是非阻塞的,并且会生成最少的事务日志 activity。

如果您选择保持当前每次要生成新序列号时更新 sequenceTable.id 列的设计,则需要确保:

  • 'current' 进程在包含所需序列号的行上获得独占锁
  • 'current' 进程然后更新所需的行并检索新更新的值
  • 'current'进程释放独占锁

虽然以上可以通过 begin tran + update + select + commit tran 实现,但实际上使用单个 update 更容易一些语句,例如:

create procedure mySequence 
AS
begin
    declare @seqNum int

    update sequenceTable
    set    @seqNum = id + 1,
           id      = id + 1

    select @seqNum
end

update 语句是它自己的事务,因此 id 列的更新和 @seqNum = id + 1 的赋值是在 update 中的独占锁下执行的交易.


请记住,独占锁会阻止其他进程获取新的id值;最终结果是新 id 值的生成将是 single-threaded/sequential

虽然从确保所有进程获得唯一值的角度来看这是 'good',但这确实意味着如果您有多个进程达到 update,则此特定 update 语句将成为瓶颈]同时

在这种情况下(大量并发 update),您可以通过减少调用存储过程来缓解一些争用;这可以通过让调用进程请求一系列新的 id 值来实现(例如,将 @increment 作为输入参数传递给 proc,然后使用 id + @increment 而不是 id + 1,使用调用进程然后知道它可以使用序列号 (@seqNum-@increment+1) 到 @seqNum.


显然(?)任何使用存储过程生成 'next id' 值的进程仅在 *ALL* 进程时才有效id 值和 b) *ALL* 进程仅使用 proc 返回的 id 值(例如,它们不生成自己的 id 值)。

如果应用程序有可能不遵循此过程(调用 proc 获取新的 id 值),您可能需要考虑将唯一 id 值的创建推到 table 这些 id 值所在的位置正在插入;换句话说,修改目标 table 的 id 列以包含 identity 属性;这消除了应用程序调用存储过程(以生成新 ID)的需要,并且它(仍然)确保为每个插入生成一个唯一的 ID。