18

特定のビジネス シナリオで、エンティティ (PK ではない) にフィールドを設定する必要があります。

私は次のようにシーケンスを定義しました:

CREATE SEQUENCE MySequence
  MINVALUE 65536 
  MAXVALUE 4294967296 
  START WITH 65536
  INCREMENT BY 1
  CYCLE
  NOCACHE
  ORDER;

Javaコードでは、次のようにシーケンスから番号を取得します:

select mySequence.nextval from dual

私の質問は:

トランザクションでこれを呼び出しselect mySequence.nextval from dual、同時に別のトランザクションで同じメソッドが呼び出された場合 (並列要求)、シーケンスによって返される値が異なることは確かですか?

最初のトランザクションからコミットされていない値を読み取ることはできませんか?

シーケンスを使用せず、シーケンスをインクリメントする単純なテーブルを使用しなかったとします。trasactinalitY がデフォルトの「READ COMMITTED」である場合、トランザクション 2 は同じ値を読み取ることができたはずです。

4

4 に答える 4

40

答えはノーだ。

Oracle は、順序によって生成される数値が異なることを保証します。並列リクエストを発行しても、RAC 環境やロールバックとコミットが混在しています。

シーケンスはトランザクションとは関係ありません。

ここでドキュメントを参照してください:

CREATE SEQUENCE ステートメントを使用してシーケンスを作成します。シーケンスは、複数のユーザーが一意の 整数を生成できるデータベース オブジェクトです。シーケンスを使用して、主キー値を自動的に生成できます。

シーケンス番号が生成されると、トランザクションのコミットまたはロールバックとは関係なく、シーケンスが増分され ます。2 人のユーザーが同じ順序を同時にインクリメントすると、各ユーザーが取得する順序番号にギャップが生じる可能性があります。これは、順序番号が他のユーザーによって生成されているためです。あるユーザーは、別のユーザーが生成したシーケンス番号を取得することはできません。シーケンス値が 1 人のユーザーによって生成された後、そのユーザーは、シーケンスが別のユーザーによってインクリメントされるかどうかに関係なく、その値に引き続きアクセスできます。

シーケンス番号はテーブルとは別に生成されるため、同じシーケンスを 1 つまたは複数のテーブルに使用できます。個々のシーケンス番号は、最終的にロールバックされるトランザクションで生成および使用されたため、スキップされたように見える可能性があります。さらに、1 人のユーザーは、他のユーザーが同じシーケンスから描画していることに気付かない場合があります。

于 2012-08-24T07:03:56.677 に答える
7

Oracle は、シーケンス番号が異なることを保証します。トランザクションがロールバックされた場合でも、シーケンスは「使用」され、別のクエリに再発行されません。

編集:「ギャップなし」に関する要件がCrisのコメントに記載された後に追加情報を追加する

要件がギャップのない一連の数字である場合、オラクル シーケンスはおそらく適切なソリューションではありません。トランザクションがロールバックするとき、データベースが再起動するとき、またはその他のシナリオが発生したときにギャップが生じるからです。

シーケンスは主に、ギャップやトランザクション コンテキストの制約に関係なく、一意の番号 (主キーなど) の高性能生成ツールとして意図されています。

設計/ビジネス/監査の要件ですべての数値を考慮する必要がある場合は、代わりに、トランザクション コンテキスト内で事前に決められた数値を使用するソリューションを設計する必要があります。これは扱いにくく、マルチスレッド環境でのパフォーマンスやロックの問題が発生しやすい可能性があります。ギャップが問題にならないように、要件を再定義することをお勧めします。

于 2012-08-24T06:57:14.497 に答える
4

sequence.nextval同時リクエストに対して(サイクルされる前に)同じ値を返すことはありません。おそらく、次の URL を確認する必要があります。

http://docs.oracle.com/cd/B19306_01/server.102/b14220/schema.htm#sthref883

于 2012-08-24T06:56:53.767 に答える
1

残念ながら、「自分の車輪」であるトランザクション シーケンスを実装する必要があります。かなり単純です-sequence_name varchar2、value、min_value number、max_value number、need_cycle charのようなテーブルを作成し、「更新待機のためにシーケンステーブルから変数に値を選択します(またはnowait-シナリオによって異なります)」。update set value = variable from previous step + 1 を発行した後、sequence_name = シーケンスの名前を指定し、クライアント側から commit ステートメントを発行します。それでおしまい。

于 2012-08-24T07:08:35.070 に答える