@TableGeneratorつかってみた

もっとJPAのこと書いていかないとなぁということで@TableGeneratorを使ってみました。
TableGeneratorという単語を見るとテーブルを生成することを意味するかのように思えてしまうのですが、そうではなくてテーブルをつかって主キーを生成するためのものだったりします。PofEAAではそのようなテーブルをキーテーブルと呼ぶらしいです。

主キーの生成というとシーケンスとかAutoIncrementとか他の方法があったりするのですが、DBによっては使えない場合があります。このテーブルを使う方法はどのDBでも実行できます。あと、ちゃんと比較したわけではないのですがパフォーマンス的に期待できるかもという特徴もあったりします。

HibernateTopLinkの両方で試してみました。

エンティティの定義と@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
TopLinkで動かした後のID_GENテーブルのデータ
GEN_ID GEN_VAL
Emp 150

Empテーブルの値hはHibernateTopLinkでまったく同じになるのですが、ID_GENテーブルのほうはちがってます。これは計算のベースになる値を格納するのか計算した結果の値を格納するかのちがいですね。たぶん。

まとめ

以下、Hibernateに関すること

  • generatorのクラスはMultipleHiLoPerTableGenerator
  • ID_GENテーブルは主キーが生成されるたびに毎回更新されるのではなく、デフォルトでは50回の生成ごとに更新される
  • DBの更新は別トランザクションで実行している(当然抜け番が発生し得るわけですがそんなの気にしないよね)
  • AutoIncrementを使うとpersistしたタイミングで毎回INSERTが実行されますが(INSERTしないとAutoIncrementされた値がとれないため)、TableGeneratorの場合はコミット時(というかflush時)にまとめてINSERTされる。
  • ロックの発生数が少ない、DBアクセスが少ない、ということでパフォーマンスが良いのかも

TopLinkのほうは動かしただけで中身をみていないです...