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から採番させる必要があります。
|
|
そんな感じです。