2017-08-04 4 views
1

これは古い質問ですが、もう一度質問しています。 実際に私はテーブルのOracleのようなシーケンスを作成し、複数のスレッドと複数のJVMのすべてのプロセスがそれを平行して打つことに使用したい。DB内に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 
+0

私はあなたのプロシージャに同期がないと思います。つまり、最初の 'select'ステートメントと' update'ステートメントに競合があります。選択と更新の中間で別のプロセスの同時選択が可能です別のプロセスの2つの同じ値を与えます。 (あなたの質問は、Javaとは関係ありません)。 –

+0

@ M.Prokhorovと同意する - これは厳密にはJavaに関する質問ではありません。それでも、なぜ単に実際のシーケンスを使用しないのですか?マルチスレッドJavaアプリケーションでは、これを何年も使っています –

+0

dbはシーケンスsybaseを提供しないため、このストアド・プロシージャは複数のJVMとスレッドから呼び出されるためです。また、私はそれが新しい値を追加したいと思うの同じバージョンで満たしているときにのみ更新が動作します、私はそれが私にうまくいくように異なる結果を与えるたびに、Javaユニットテストから500呼び出しでそれをテストしました。私はいくつかの事が当てはまるかもしれないことを確認するよう頼んでいます。 – user460293

答えて

1

あなたは、新しいシーケンス番号を生成するたびにsequenceTable.id列を更新するあなたの現在のデザインを維持することを選択した場合、あなたは確認する必要があり:

  • 「現行」のプロセスが排他的ロックを取得します「カレント」プロセスは、所望の行を更新し、新たに更新された値を
  • 「カレント」のプロセスを取得所望の配列番号
  • を含む行は、排他ロックを解除

上記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列に割り当てられ、updateのトランザクション内で排他ロックによって@seqNum = id + 1の割り当てが実行されます。


排他ロックは、新しいID値を取得するから、他のプロセスをブロックすることに留意してください。結果は新しいID値の生成がシングルスレッド/シーケンシャルであることです。

すべてのプロセスが一意の値を取得するという観点からはこれは「良い」ですが、この特定のupdateステートメントがupdateに複数のプロセスが同時に起動しています。

このような状況では(大量の同時実行update)、ストアドプロシージャを頻繁に呼び出すことによって競合を緩和することができます。これは、呼び出し側プロセスが新しいID値の範囲を要求するようにすることで実現できます(たとえば、@incrementを入力パラメータとしてprocに渡し、id + 1の代わりにid + @incrementを使用します)、呼び出しプロセスはシーケンス番号(@[email protected]+1 )から@seqNumまでです。


明らかに(?)格納されたprocを使用して '次のid'値を生成するプロセスは、* ALL *のプロセスがa)常に新しいid値のためにprocを呼び出し、b)* ALL *プロセスは返されたid値procによって(例えば、彼ら自身のid値を生成しません)。

このプロセスに従わない可能性がある場合(procを呼び出して新しいid値を取得する場合)、これらのid値が挿入されているテーブルにユニークなid値の作成をプッシュすることを検討してください。言い換えれば、identity属性を含むようにターゲットテーブルのid列を変更します。これにより、アプリケーションが(新しいIDを生成するために)ストアドプロシージャを呼び出す必要がなくなり、各挿入に対してユニークなIDが生成されることが保証されます。

+0

ニース!ありがとう... – user460293

1

ASEでシーケンスをエミュレートすることができます。活動の必要な型を達成するためにreserve_identity機能を使用します。

create table sequenceTable (id bigint identity) 
go 

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

このソリューションは、非ブロッキングで、最小限のトランザクション・ログ・アクティビティを生成しません。

+0

これは複数のJVMでも重複した値を提供しないことを保証しますか? – user460293

+0

データベースから通常のIDENTITYメカニズムを使用しています。データベースはそれを保証するはずです。しかし、覚えておいてください。 2番目のIDを使用する場合は、次のテーブルを作成する必要があります。 –

+0

@ user460293; Adamがあなたの 'sequenceTable.id'カラムを' int'から 'bigint identity'に変更したことに注目してください。 'int'と' bigint'の使用はあなたが決めるべきですが、 'reserve_identity()関数が正しく動作するためには' identity'属性を指定する必要があります。 – markp

関連する問題