Ads by Google [--/--/-- (--)]
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

役に立ったらぽちっとよろしく。 人気ブログランキングへ

JPAでは保存・復元時にプロパティ経由かフィールド経由か選べる。

オブジェクト指向の入門本を読むと、フィールドを直接使うよりプロパティを通してアクセスした方がフィールドアクセス時の必須操作を必ず実行させるように出来るので、自前でフィールドにアクセスするよりも遥かに安全。だからなるべくプロパティを使うように!と書いてある。…ので、ここもプロパティでしょ!と思ったら…。

プロパティの場合だと、publicとprotectedにしか使えない。これだとエンティティクラスのAPIを公開する時にそれらの部分も必ず公開される事になる。たとえ、それがエンティティの作成時刻の様にただ一度設定されるものであっても、再設定の機会をライブラリ使用者に与えてしまう。これはまずい…。ちなみにもっと酷い場合は以下の様になる。

/* 知ると消される国家機密. */
@Column(name="danger_info")
public String getDangerInfo() {
    return dangerInfo;
}
/* 落書厳禁マフィアの隠れ家. */
public void setDangerInfo(String dangerInfo) {
    this.dangerInfo = dangerInfo;
}
private String dangerInfo;

これではプログラマの命が幾つあっても足りない…。そんなこんなで、仕方なくフィールド経由にするか…と鬱々なる……けど、案外そっちのが妥当と気づいた。

てのはMementoパターン[Gof]がこれに似てる。Mementoパターンも保存復元の内部動作を担当するクラスに対しては保存情報(記念品:Memento)の中身へのアクセスを許可している。つまり、保存復元というテーマを扱う以上、通常の小さなインタフェースの他に、保存復元を担当する部分に提供するprivateでもアクセス出来るインタフェースを備えるのはごく自然な流れである。

一方、エンティティのフィールドにおいても、保存・復元を担うJPAはprivateでもアクセスするようになっている。つまり、先のMementoの例と似ている。しかもこの場合、JPAが直に元のprivateフィールドにアクセスするので記念品作りは必要ない。しかも、別にそのフィールドに新たなプロパティをかぶせてはいけないって事ではないのでロジック部分もきちんと作りこめる。というわけでJPAエンジンのアクセスはフィールド経由でしょっ!!て事になる。

ところが今度は…「じゃぁプロパティ版は何のためにあんの?」って疑問が出てくる。自分ではさっぱり分からなくなったので、サクッとググっとしてみると…

Adam Bien's Weblog
Property Based Access in JPA - is an Emerging Antipattern

発見!!…どうやらプロパティ版はアンチパターンだと…。ただ、必要になる場面もあるらしく、Detached状態にあるエンティティを値オブジェクトとして使う時とかがそれらしい。つまり、例え遅延ロードが有効になっていてManagedの時にロード(フェッチ)が行われてなくて、Detachedになっちゃっても取り敢えず何とかシリアライズ出来るよ言う事らしい。うーん、なるほど!!

役に立ったらぽちっとよろしく。 人気ブログランキングへ

続きを読む »

JPAの各製品にはセカンドレベルキャッシュを持つ物が多い。もちろん各製品独自の機能で切る事は出来るんだけど。…JPA1.0の仕様書では特にその事について触れていないっぽい。そして一人のおバカが次のような落とし穴にはまった。

EJBコンテナによるトランザクション開始直後にfindを発行したのにクエリが流れていないらしい事をログで確認。しかも、クエリは流れていないのにエンティティはmanaged状態で返ってきてる。トランザクション開始したばかりなのでpersistence contextにはまだ何のエンティティもないはず…なんじゃこりゃぁー!と思う。で、ここで二次キャッシュの存在に賢い人は気づくはず…が、あるバカは仕様書をしらみ潰しに調べ、拡張永続コンテキスト(TransactionType.EXTENDED)がしらんまに適用されたのか、と勘違いする。で、まる一日格闘した後、clearメソッドを最初に発行してもまだキャッシュされている事に気づき、ようやくpersistence context以外にキャッシュしてる黒幕がいると悟ったバカでした。

で、どうやらこのバカは性格まで悪いらしくJPAの仕様の書き方とそれを実装する各製品にケチをつけだした…。以下その言い分…。

  • やい!JPA!!二次キャッシュに気づけんバカによる操作は"Out of specification"だと思ってるんだろう!でもあんたに従うとDBと正確に同期を取る場合、select系Queryの後に一件毎にrefleshを呼ぶはめになるだろぅが!どれだけ無駄なクエリが流れると思ってんだ!バカって言う奴が馬鹿!
  • やい!Toplink!!二次キャッシュはデフォルト切っとけ!最初にレーシングカーに乗せるな!バカには遅くてもいいから安全なのを渡せ!ていうかお前なんか最初の交差点でスリップして死んじまえ!

…なんか最近変なバグまがいの仕様が増えて超鬱なバカでした…はぁ…。(ちなみにToplinkは主キーが指定されているクエリだけ二次キャッシュを使うみたい…。)

で、それはいいとして、まだEarly Draftの段階だけどJPA2.0からは二次キャッシュがちゃんと明文化されるとさ…で、Toplink EssentialはEclipse linkになるってさ…。ふぁっふぁっふぁいとぉ〜っ。

役に立ったらぽちっとよろしく。 人気ブログランキングへ

なんだこれは! [2008/05/10 (土)]

タイトル通りなんですが、またまたToplinkです…。FetchType.LAZYとラージオブジェクトの使い方に関して…。

データベース上のLOB形(BLOBやらCLOB)を格納したレコードにそれらのカラムを含まないクエリを投げておき、実際に必要になった時だけそれらのカラムを取得する。これはたぶんそんなレアな事ではないはず。例えば、個人のプロフィールと一緒に顔写真もDB上に格納し、普通の業務ではプロフィールのカラムだけを処理し、顔写真のいる書類の時だけそのカラムも処理する。こうすれば普通の業務で100人分のデータが必要って時に、何十キロバイトもある顔写真×100人分の巨大なデータを受け取らなくて済む。この場合、顔写真のカラムに対応するプロパティに@Basic(fetch=FetchType.LAZY)@Lobってな感じになる。

が、しか〜し、、、glassfishのログを追跡していると、何やら怪しげな内容が…

oracle.toplink.essentials.session.file:/C:/Sun/SDK/domains/domain1/applications/j2ee-apps/ear/ejb_jar/-ejb.ejb_or_metadata|_ThreadID=10;_ThreadName=main;_RequestID=8baaf9b2-fd82-4307-bbb9-c0dfc6b34821;|Ignoring LAZY fetch type on element [private byte[] entity.PictureItemBean.image] within entity class [class entity.PictureItemBean]. All basic mappings default to use EAGER fetching.|#]

な、何これ?嘘!勝手にEAGERにされちゃった…。いや、確かにJPAの実装には、LAZYはあくまでヒントだから別にそうしなくてもいいよってあるけど…。ここ一番美味しい所では?でも、よく調べるとToplinkのサイトでも、確かに@Basicマッピングは問答無用でEAGERだって書いてるけど…。嘘ぉーん。えー…結局よく調べなかったおいらが悪いってオチですか?…み…認めん…こんなん仕様にしやがって…ほとんどバグじゃないか…。た…例え…お天道様が認めても…おいらは…おいらは…自分の非だけは認めんぞー!!くわぁー!(泣)

役に立ったらぽちっとよろしく。 人気ブログランキングへ

今日も相変わらず、Toplinkのバグは手強い…。普通にフィールドにアクセスしただけでInvocationTargetExceptionやらjava.lang.NoSuchMethodErrorが発生した。…で、毎度の事だけどバグ対策のサイトは英語…うーんFetchTypeを統一すると治るとか…。たぶんToplink内部の動的ウィービングが関係しているんだろうけど…そんな事を知らんユーザだとこれは面食らうと思う…。ぶっちゃけ、ホコ天で車にはねられたようなものだ…。で、結果論なんだけど…ここしばらくToplinkと付き合ってきて思ったのは、バイトコード変換はやっぱりバグの温床になってる気がする。

以前Javaのバイトコード変換についての議論があって、で危険だからやめよう→どこがそんなに危険なんだ?→こんな素晴らしい機能なのに→あーだこーだ…っていう議論があった。

おいらが思うにバイトコード変換は何も危険でないし、それが出来るのはJavaの実行環境がうまく出来ててその上きちんと仕様化されてるJavaの長所の証明みたいなもんだと思う。そして、何より応用範囲が広くて素晴らしい技術だと思う。

…けども、やっぱし問題もある。最大の問題は初心者と上級者の隔たりを大きくしてしまう所。実現したい事は動的ウィービングとかそんなシンプルな事なのに、それが可能なのは技術的、時間的に見てフレームワークの開発者だけってのは何かおかしな気がする。で、その上級者にとってもやっぱり茨の道であるのは変わりない。おかげでToplinkはバグだらけなわけで…。同じ事がもしJavaの言語機能としてあれば…きっとここまでバグは出ないはず…。

思うにJavaの言語としての性能の方が、VMの性能に追っつけてないからバイトコード変換って技術が生まれたのだと思う。で、きっと同じ理由でJRubyとかも作られてるのかな…。うーんだとするとJavaの将来は…って将来考えてる場合じゃない。将来より今…どーするよこのToplinkのバグ…全部LAZYか全部EAGERかって、何そのAll or Nothingみたいなの…。

役に立ったらぽちっとよろしく。 人気ブログランキングへ

続きを読む »

O/Rマッピングシリーズ第三回の今日は、前回おいらが閃いた方法を実際に実装して、より深くO/Rマッピングの泥沼へとはまります。…え?シリーズだったのって?…単に泥沼から出れないだけです…爆。

なお今回のパートナーも前回と変わらずToplink。おいらは面倒くさがりなので、Hibernateが少しいい位じゃ、glassfish同梱のToplinkにしがみつく。…そして、はまる度にToplinkどうよ…とぶーたれる。おぃ!無料で使ってるくせに悪質クレーマーかよ!って話は置いといて。(/^_^)/

さて、前回、担当者の本体情報を抜き出してそこに社員とアルバイトからOneToOne関連を張った。実装にあたって社員とアルバイトそれぞれから本体情報にアクセスするのは面倒なので、やっぱり抽象クラスを作った。

クラス図

…もちろんこの抽象クラスはDBのテーブルと直接関係は無い。なので@Entityは不要。JavaSEではEEと違ってpersistence.xmlにエンティティクラスを書く必要があるけど、それも不要…と思ってJUnit(JavaSE環境)でテストした…いつのまにか起動しなくなってる…。吐いたエラーは

java.lang.LinkageError: loader constraint violation: loader (instance of sun/misc/Launcher$AppClassLoader) previously initiated loading for a different type with name "entity/Albite"

で、よく調べたらtoplinkのバグ。glassfishのサイトで対策があって英語で意味不明なんだけど、persistence.xmlに基底クラスを書き足すと治るとか…そんな事が書いてる…ような…気がする…。嘘ぉ〜ん…と思いつつ半信半疑やってみると…げっ本当だ!実際にうまく動いてびっくり、自分の英語が当ってびっくり!二重にびっくりだよまったく…

役に立ったらぽちっとよろしく。 人気ブログランキングへ

続きを読む »

Copyright © ふらふら技術者の日記 All Rights Reserved.
Powered by FC2 Blog FC2ブログ