2016-10-17 11 views
0

ここでは奇妙な状況があります。トリガとシーケンスを使って自動インクリメントを実装しました。私は、Hibernateを使用する私のWebアプリケーションから私のテーブルにデータを挿入します。私は私のマシン(Netbeans)と私のオフィスネットワーク(WebアプリもWildflyで私たちのサーバーに配備されている)でWebアプリケーションをテストします。シーケンスおよびトリガーの問題を伴うOracle自動インクリメント

一意の制約(プライマリキー)のために例外が発生するまで、常にうまくいきました。次に、問題はIDの値を生成するシーケンスであることがわかりました。例は、私のテーブルxtableの場合、その配列のLAST_NUMBERは78400で、xtableで最大のIDは78308ですが、シーケンスのNEXTVALは、私は次のようにシーケンスを作成したので、それが起こるかは考えていません78304.です:

CREATE SEQUENCE XTABLE_SEQUENCE INCREMENT BY 1 START WITH 1; 

私はシーケンスを更新し、テーブルに最大(ID)よりもそのNEXTVALが大きくなるようにするには、次のを試してみましたが、nはここ

declare 
maxval number(10); 
begin 
    select max(ID) into maxval from XTABLE; 
maxval := maxval+1; 
execute immediate 'DROP SEQUENCE XTABLE_SEQUENCE'; 
execute immediate 'CREATE SEQUENCE XTABLE_SEQUENCE START WITH '|| maxval+50 ||' INCREMENT BY 1'; 
end; 

を挿入した後、私はまだ同じ結果を得ていることは、トリガー文は次のとおりです。

create or replace TRIGGER xtable_sequence_tr 
BEFORE INSERT ON xtable FOR EACH ROW 
WHEN (NEW.id IS NULL) 
BEGIN 
SELECT xtable_sequence.NEXTVAL INTO :NEW.id FROM DUAL; 
END; 

または、私が直面している問題を回避するために、Oracleで自動インクリメントを実装する適切な方法は何ですか?ある時点で、私はテーブルの最大IDがトリガーで使用されたsequence.nextvalよりも大きくなるという事実が原因で(私にはなんの理由がわからないので)プライマリキーのユニークなキー制約違反を取得し始めます。それを引き起こしているものとそれを修正する方法は?

+0

'cache 100'ではなく' nocache'を使ってシーケンスを再作成するとどうなりますか?また、データベースはRACデータベースですか? – Boneist

+0

トリガーについて言及しました。私たちに彼らのコンテンツを見せてください。また、hibernateによって生成されたSQL文 –

+0

'シーケンスのlast_numberは78400、xtableの最大IDは78308ですが、シーケンスのnextvalは78304です。'しかし、Oracleシーケンスはnextval値をロールバックできません。手動で変更しましたか? – AlexSmet

答えて

1

正直言って、この投稿は非常に混乱しています。

あなたが

"私のテーブルxtableの場合は、その配列のLAST_NUMBERはxtableのmax idが78308で、78400ですが、シーケンスのNEXTVALが78304.である"、と述べていますそれは私に語っ何

  1. が78400としてシーケンスの最後の番号を持つことである、メモリにキャッシュし、それは、彼らが唯一することができ、キャッシュされている78300. 100一度のシーケンスで開始しなければならないであろう100の系列がありましたサーバが再起動されない限り使用され、あなたのケースでは78400を表示するようにシーケンスの最後の値を変更しますが、次の挿入によって使用されるメモリにキャッシュされているシーケンスだけであるその場合データベースが再起動されない限り、キャッシュされたシーケンス番号は失われます。 BTWシーケンスキャッシュは、異なるセッション間で共有されます。

  2. 「が、シーケンスのNEXTVALは変更されませんでした」もう一度あなたがシーケンスの最後の値が、それはそうではありませんsequence.nextvalと同じであるということを想定しているを。 dba_sequencesビューを照会しLast_NUMBER列を見ると、最後の値はCACHEDであり、sequence.nextvalによって生成された最後の値ではなく、表で使用されます。

正直なところ、これを解決するには多大な努力を要しません。

A.行を挿入するたびに、プロシージャやトリガで実行する代わりにシーケンスを使用し、その後シーケンスに戻ってくることを確認します。混在しないでください。(直接挿入を使用すると、1、2、3のようなエントリが存在する可能性があるため、順序が保証されていないことを覚えておいてください。 、あなたが本当に常に順序をしたい場合は、代わりに手順や他の手段を使用してシーケンスを使用しないでください)。

B.テーブルでmax idを最初に照会してから、シーケンスを削除してから、もう一度再作成するのではなく、

最初にを削除し、テーブルから最大値を取得し、その時点以降のシーケンスを作成します。これは、テーブルの最大IDを見つけるためにクエリを実行していたときにコミットされた可能性がある他のセッションからの汚いトランザクションによって既に使用されている可能性のあるシーケンスの記録を失うのを防ぎますが、それでも安全ではありません。

より良い結果を得るには、シーケンスを削除する直前に使用する、以下のクエリで示される値の1つ上の値から始まる新しいシーケンスを作成するだけです。

基本的に私が言っていることは、現在キャッシュされているものよりも大きな値で新しいシーケンスを作成することです。

+0

私がしたことは、max(id)+ 1000という開始番号を持つ新しいシーケンスを作成したことです。一時的に問題を解決した後、webappはプライマリキー列のユニークな制約違反によりエラーメッセージを再度表示し始めましたログ)。 sequence.nextvalをチェックすると、関連するテーブルのmax(id)よりも小さくなります。 – bkn

0

私はその問題を抱えていた状態を考え出しました。事は、私が250000の挿入クエリを含むファイルを実行するなど、何万ものレコードをロードしているうちに、誰かが同時にレコードを挿入しようとしていました(私のWebappを通じて)。おそらく、2つの挿入クエリが同時にどこで実行されるのかという問題が発生しました。

+0

私は同じ問題をユーザーだけがテーブルを更新し、レコードを挿入していないことがあります。そして、私は最後のシーケンスの方法をポイントで20kレコードで最大IDの後ろに見つけました。そして、ユーザーのアップデートがどのように起こっているのか把握しようとしています。 problem.But私の場合、プロシージャはレコードを削除して追加しますが、シーケンスは挿入時に次の値を取得する必要があります。 – Evangelos

+0

これはやっかいですが、私はまだ同じ問題を抱えていますが、まだ原因を把握していません。今度はids1433と1434がすでに挿入されているので、シーケンスのCURRVALは1433だったので1434となっていたので「ユニーク制約」がスローされたので、次のNEXTVALの呼び出しでは1435 。 – bkn

関連する問題