今更ながらGenericsのすごさに驚嘆しているわけで。
ActiveObjectsの中にはトランザクションを保証するためのTransactionクラスがある。Transactionクラスのシグネチャはこんな感じ。
public abstract class Transaction<T>; public T execute() throws SQLException; protected abstract T run() throws SQLException; protected final EntityManager getEntityManager();
で、使い方はこんな感じ
EntityManager manager = new EntityManager(provider); Person p = new Transaction<Person>(manager){ @Override protected Person run() throws SQLException { // このときINSERT文発行! Person p = manager.create(Person.class); p.setName("Hiroki Kondo"); // このときUPDATE文発行! p.save(); return p; } }.execute();
Transactionクラスは抽象クラスなので、こんな感じに匿名クラスを作って使ってやる訳ですね。PersonクラスをGenericsのTの部分に指定する事で、runメソッドの返値がPersonになっている訳ですよ。executeメソッドの中でrunが呼ばれて、その結果を返すようになっているので、Transactionの外でPersonのインスタンスが受け取れるわけです。無事にrunメソッドが終わればcommit、SQLExceptionなどが飛べばrollbackします。
Collectionクラスでよく使っているGenericsですが、匿名クラスの返値をオーバーライドで指定して使う方法は見たことがなかったんでスゲーと驚いている訳です。これだからコードリーディングは止められません。
ActiveObjectsでSQLログを出力する
今日は最近はまり始めたActiveObjectsのTipsです。まずSQLログを出力するにはどうするのか、ですが、EntityManagerのJavaDocに書かれてました。
EntityManager manager = new EntityManager(provider); Logger.getLogger("net.java.ao").setLevel(Level.FINE);
EntityManagerのインスタンスを作った後にLevelがOFFになっちゃうので、設定しなければならんとですよ。中をちょろちょろっと見てたらJavaのlogging APIを使っているんで、プロパティとかを設定すればいいもんだと思い込んでいろいろ設定してみたんですができんわけですよ。
O/RマッパーActiveObjects
僕はO/Rマッパーについていくつも調べたことがありません。が、一時期Hibernateを使ってみようとしたことがあります。2年くらい前に「Hibernate in Action」が出て、それを元に使ってみようと頑張ってみましたが、モノの2週間くらいで挫折しました。
当時は3系が出たての頃です。2系の補助ツールは充実していたのですが、3系の補助ツールは微妙にあったくらいで、Hibernate-anotationも出たてでした。なので直でXMLをゴリゴリ書き直さないといけません。これがどうにも面倒くさい。
名前を忘れてしまいましたが、ER図を書くと関連を定義したXMLを吐いてくれる
Hibernateの補助ツールがありました。永続化したいモデルを修正するためにER図を書き直さないといけないのは遠回りで面倒くさかったんです。どちらかと言えば、モデルを書いておくと、それを元にER図として見えるようになってくれるとうれしかったんですが、そういう都合のいいツールを見つけられませんでした。
Hibernateも出始めた頃はEJBに対するアンチテーゼとして登場してきましたがHibernateも既に充分過ぎるくらい重厚なフレームワークになってしまいましたね。フットプリントが2MBってデカいですよ…。
ということで、ここ最近薄いO/Rマッパーが欲しくなり、探してみました。
見つかったのがActiveObjects。Active Recodesみたいなモノを目指してるらしいです。これはいいですよ。こんなことができます。
- 永続化したいモデルのインターフェースを切るとそのインターフェースを元にDBのスキーマを作ってくれる/マイグレートしてくれる
- エンティティをsave()したときにDBの値が更新されます。(宣言的トランザクションみたいなものはないようです。また、COMMITのタイミングもフレームワーク内で特に規程されていません)
使ってみようと思っている対象が組込みDBなのでこれくらい小さなもので充分なのです。DBのスキーマを作成するDDLも意識しないでいいのは楽ちんす。
5/6 追記
DBの値が更新されているとメモリ上の値もきちんと反映されんのねん。つーか、毎回問い合わせる感があるけどいいか。