@TableGeneratorつかってみた
もっとJPAのこと書いていかないとなぁということで@TableGeneratorを使ってみました。
TableGeneratorという単語を見るとテーブルを生成することを意味するかのように思えてしまうのですが、そうではなくてテーブルをつかって主キーを生成するためのものだったりします。PofEAAではそのようなテーブルをキーテーブルと呼ぶらしいです。
主キーの生成というとシーケンスとかAutoIncrementとか他の方法があったりするのですが、DBによっては使えない場合があります。このテーブルを使う方法はどのDBでも実行できます。あと、ちゃんと比較したわけではないのですがパフォーマンス的に期待できるかもという特徴もあったりします。
エンティティの定義と@TableGeneratorの指定
こんな感じ。
@Entity public class Emp { @Id @GeneratedValue(strategy = GenerationType.TABLE, generator = "emp_gen") @TableGenerator(name = "emp_gen", table = "ID_GEN", pkColumnName = "GEN_ID", valueColumnName = "GEN_VAL", pkColumnValue = "Emp") private Integer id; private String name; // getterとsetterは省略 }
DDL
エンティティとキーテブルのDDLはこんな感じ。
テーブル名やカラム名が上の@TableGeneratorで指定した値に対応しているのがなんとなくわかると思います。
ID_GENテーブルの1レコードがエンティティと主キーの値のペアを表しています。
create table Emp( id int primary key, name varchar ) ; create table ID_GEN ( GEN_ID varchar primary key, GEN_VAL int ) ; insert into ID_GEN values('Emp', 0) ;
実行
S2JUnit4を使って動かしてみます。
Empエンティティを101個永続化しています。
@RunWith(Seasar2.class) @TxBehavior(TxBehaviorType.COMMIT) public class EmpTest { EntityManager em; public void test() throws Exception { persist(101); } private void persist(int times) { for (int i = 0; i < times; i++) { Emp emp = new Emp(); emp.setName("foo" + i); em.persist(emp); } } }
実行した結果
Hibernateで動かした後のID_GENテーブルのデータ
GEN_ID | GEN_VAL |
---|---|
Emp | 3 |
まとめ
以下、Hibernateに関すること
- generatorのクラスはMultipleHiLoPerTableGenerator
- ID_GENテーブルは主キーが生成されるたびに毎回更新されるのではなく、デフォルトでは50回の生成ごとに更新される
- DBの更新は別トランザクションで実行している(当然抜け番が発生し得るわけですがそんなの気にしないよね)
- AutoIncrementを使うとpersistしたタイミングで毎回INSERTが実行されますが(INSERTしないとAutoIncrementされた値がとれないため)、TableGeneratorの場合はコミット時(というかflush時)にまとめてINSERTされる。
- ロックの発生数が少ない、DBアクセスが少ない、ということでパフォーマンスが良いのかも
TopLinkのほうは動かしただけで中身をみていないです...