自動採番
自動採番とは?
(主には)主キー(PrimaryKey)の値において、連番を生成する仕組みのことを示します。
自動採番には大きく二つの方法があります。
- シーケンス
- Identity
これら方法は、DBMSによってサポート状況が変わります。DBMSごとの取扱いでご確認下さい。
自動採番の自動化
DBFluteでは、あらかじめ自動採番の情報を利用して、 (シーケンス、Identityの違いに関わらず)登録時に自動採番の処理(採番処理の実行、Entityへの格納など)を自動化します。
自動採番を自動化した登録処理(PKの自動設定) {MEMBER_ID} @Java
Member member = new Member();
// you don't need to set
//member.setMemberId(3);
member.setMemberName("FOO");
...
memberBhv.insert(member);
// you can get the auto-incremented value after insert
Integer memberId = member.getMemberId();
シーケンス
シーケンスの設定
シーケンスは、テーブルと関連付かない独立したデータベースオブジェクトです。 そのため、汎用的に利用ができますが、PKの値に利用するなどの定型的に利用される場合においては、 その関連性は人(の頭の中で)しかわからないため、そのままでは仕組みで解決することはできません。
DBFluteでは、テーブル(のPK)と利用するシーケンスの関連性を定義することで、 登録(insert)時にシーケンスを使った自動採番が有効になります。sequenceDefinitionMap.dfprop において、その関連性を定義します。
設定例 @sequenceDefinitionMap.dfprop
map:{
; PURCHASE = SEQ_PURCHASE
; MEMBER = SEQ_MEMBER
; MEMBER_LOGIN = SEQ_MEMBER_LOGIN
; PRODUCT = SEQ_PRODUCT
}
serial型のシーケンスは設定不要
PostgreSQLの serial 型、および、bigserial 型によるシーケンスは、DBFluteで特別な処理を行ってテーブルとの関連性を自動で判別するため、設定は不要です。 (但し、DBFluteにおけるシーケンスキャッシュ機能を利用する場合は、明示的な設定が必要)
登録時にPKの指定は不要
設定されたテーブルでは、登録時にPKの明示的な指定は不要です。内部的に自動でシーケンスで採番された値が Entity に格納されます。
シーケンスを利用した登録処理(PKの自動設定) {MEMBER_ID} @Java
Member member = new Member();
// you don't need to set
//member.setMemberId(3);
member.setMemberName("FOO");
...
memberBhv.insert(member);
// you can get the sequence value after insert
Integer memberId = member.getMemberId();
明示的にシーケンスを取得
設定されたテーブルの Behavior には、明示的にシーケンスを取得するメソッドが生成されます。 登録時はPKの指定なしで内部的に自動でシーケンスが利用されるため、このメソッドは基本的には利用することが少ないですが、 例えば、業務的な要件で登録前にシーケンスの値が必要になるような場合は、このメソッドを使ってシーケンスを取得します。
シーケンスを明示的に取得 {MEMBER} @Java
Integer seq = memberBhv.selectNextVal();
明示的に取得したシーケンスの値を登録処理で利用したい場合は、Entity のPKカラムにその値を設定して登録処理を呼び出します。その場合、内部的には設定された値を優先し、内部的なシーケンスの取得は行いません。
シーケンスを明示的に取得 {MEMBER} @Java
Integer seq = memberBhv.selectNextVal();
member.setMemberId(seq);
member.setMemberName("FOO");
...
// 'seq' is used without internal sequence getting
memberBhv.insert(member);
シーケンスキャッシュ
DBFluteにて、シーケンスの発行コストを抑えるためのキャッシュ機構があります。
PK以外のカラムのシーケンス
PK以外のカラムに対するシーケンスを利用する場合は、sequenceDefinitionMap.dfprop にてテーブル名に続きカラムまで指定します(@since 0.9.7.8)。
設定例 @sequenceDefinitionMap.dfprop
map:{
; PURCHASE.PURCHASE_COUNT = SEQ_PURCHASE_COUNT
}
すると、Behaviorに selectNextValFor[column-name]() というメソッドが生成され、関連付いたシーケンスのシーケンス値を取得することができます。
ただし、PK以外のカラムに対するシーケンスでは、以下のものがサポートされません。
- PostgreSQLの serial 型シーケンスの自動認識 (dfpropでの明示的指定が必ず必要)
- シーケンスキャッシュのdfprop設定による利用 (オーバーライドで利用できる)
- ReplaceSchemaでのシーケンス値の調整
- 登録処理時のEntityへの自動設定
PK以外のカラムのシーケンスは、業務的な独自のタイミングで採番されることが想定されるため、 登録処理時のEntityへの自動設定はありません。明示的に selectNextVal...() を呼び出してEntityに明示的に設定する必要があります。 (登録のたびに自動設定するようなカラムは既にPKと言えるカラムです)
そう言う意味では、selectNextValFor[column-name]() というメソッドは、単に論理的にカラム名がメソッド名に付与されているだけで、物理的な制約は何もありません。
Identity
Identityの設定
Identityは、テーブルのカラム(主にPK)と関連付く機能で、仕組みで解決しやすいものです。
DBFluteでは、メタデータとしてテーブル(のPK)とIdentityの関連性を取得するため、 特に設定なしで登録(insert)時にIdentityを使った自動採番が有効になります。
登録時にPKの指定は不要
Identityを利用するテーブルでは、登録時にPKの明示的な指定は不要です。insert文の列挙項目としてPKカラムが除外され、DB上で採番されます。 (Entity にPK値が指定されていてもそれは無視され、必ず Identity で採番されます)
また、採番された値は、insert処理後に自動で Entity に格納されます。
Identityを利用した登録処理(PKの自動設定) {MEMBER_ID} @Java
Member member = new Member();
// you don't need to set
//member.setMemberId(3);
member.setMemberName("FOO");
...
memberBhv.insert(member);
// you can get the identity value after insert
Integer memberId = member.getMemberId();
明示的な値の登録はオプション
Identityカラムに対するアプリで明示的に指定した値での登録は、varyingInsert(entity, option) にてオプション指定で実現できます(@since 0.9.7.8)。 ただし、実際に登録できるかどうかは DBMS の仕様と設定に依存します。
SchemaHTMLでの表示
Docタスクで自動生成される SchemaHTML では、PKカラムに自動採番の設定がされているかどうかを確認することができます。
Exampleのススメ
dbflute-mysql-example では、MySQLのIdentityを利用してテストケースの中で登録処理をしています。また、dbflute-postgresql-example では serial 型のシーケンス、dbflute-oracle-example では、通常のシーケンスを使って、テストケースの中で登録処理をしています。 (他のほとんどのExampleでも同様に利用されています)