JPAでシーケンスを使ってIDを自動採番する場合の注意点
Oracle シーケンスのデフォルトはNOORDERである罠 の続きです。
JPAでEntityのIDを自動採番するとき、DBMSがOracleの場合はシーケンスを使うことになります。シーケンスを使う場合は、@GeneratedValueのstrategyプロパティにGenerationType.SEQUENCEを指定します。たぶんGenerationType.AUTOでもシーケンスになります。(GenerationType.AUTO を指定するとはDBMSによって適切な採番方法が選択されます)
|
|
SequenceGeneratorは、デフォルトではシステムでひとつのシーケンス(名前はhibernate_sequence)を共有で使用します。該当テーブル専用のシーケンスを使う場合は@SequenceGeneratorのsequenceNameプロパティで指定することができます。以下の例ではuser_id_seqがシーケンスオブジェクト名です。
|
|
SequenceGeneratorは採番都度シーケンスにアクセスして採番するのではなく、あらかじめ一定の採番枠を確保し、その採番枠内の増分であればDBアクセスを発生させないようにしています。
この採番枠は@SequenceGeneratorのallocationSizeというプロパティで指定でき、デフォルトは50となっています。
また、user_id_seq.nextvalした時にallocationSize分増加している必要があるので、allocationSizeとシーケンスのincrement byは一致している必要があります。(事実、Spring Bootにおいてspring.jpa.hibernate.ddl-auto=updateとしてシーケンスオブジェクトを自動作成するとincrement by 50のシーケンスが作成されます。)
しかし、これには一つ問題があり、同じテーブルのIDを採番するSequenceGeneratorインスタンスが複数存在すると(つまり複数のアプリケーションサーバが存在するLB構成だと)、インスタンスAは1~50、インスタンスBは51~100の枠内でそれぞれ採番することになるので、テーブルのIDは1, 51, 2, 52...のように番号の戻りが発生してしまいます。これは Oracle シーケンスのデフォルトはNOORDERである罠 と同じ問題です。
このため、IDに対して順序を期待する場合はallocationSize = 1を指定して都度SEQUENCEから採番させる必要があります。
|
|
そんな感じです。