改めhibernate(自体は)悪くない
2005年10月22日(土) 09:57
hibernateを利用してはいけない5つのシチュエーション(リンクは記事最下部の関連コンテンツにあります)では、
多数の方からそれはおかしいという指摘をいただきました。
特にkoichikさんは私の代わりに様々な検証を行ってくださり、そのおかげでやっとhibernateの癖
のいくつか知ることが出来ました(いや、ドキュメントには書いてあるんでしょうが)。
納得がいかないと頑張っていたシチュエーション4(同一Transaction内でセレクトした全てのオブジェクトをTransactionコミット時に勝手に更新)についてもhibernateの使用方法、癖を理解していなかったために陥った誤った認識でした(余裕が出来てコードを見たとたんにへこんだ)。
hibernateの仕様を理解して使用する分にはhibrenateに問題はありません。
#ただ癖がいろいろあることは確かですが。
一、知っておくべきこと
シチュエーション1で、関連の設定を削除しましたが関連の設定を削除してもなお、表示用には本当のPOJOに値をコピーすべきです(POJOのひな形作成をテーブルから自動で行うantタスクを作りました、一番下にはっつけてあります)。
シチュエーション4という誤った思いこみをした原因はここにありました。
middlegenで生成したhbmをhibernate-synchronizerでJavaコード生成すると4つのJavaのファイルができます。
そのうちのTableと同じ名前のクラスはコンストラクタのみで構成されており、かつコンストラクタは「ここからここはさわるな」的なコメントで囲まれています。当然のようにさわってはいけない領域の外に継承元のクラスにあるアクセサメソッドを上書きしてしまいました。
koichikさんの検証にもあるとおり、Transaction内でセレクトしたオブジェクトが更新される条件は二つあります。
1.セレクトしたオブジェクトの価を変更した場合
2.セレクトしたオブジェクトの価が変わったと判断された場合
もうおわかりでしょう。1と2は同一の状態です。
hibernateはセレクトした時点でのデータを保存し、Tranasctionが終了した時点でのデータと比較して更新すべきオブジェクトを確認しています。
そのデータの比較に使用されるのがTableと同じ名前のクラスのアクセサです(つまり継承元のクラスのアクセサ)。
#データの比較をアクセサ経由でなくプロパティで行わせることも設定で可能なようです
一、知っておくべきこと
hibernateのセッションは、ただのデータベースセッションとして認識してはいけません。
hibernateは単なるO/RマッピングツールではなくJavaのオブジェクト永続化機構として見るべきです。
hibernateのセッションオブジェクトはDBのプロキシとして動作します。
セレクトしたオブジェクトについても、新規に作成してsessionにsaveしたオブジェクトについてもsessionが責任を持ちます。
・sessionに一度責任を持たせたオブジェクトをsessionから解放するにはあえて指示する必要があります。
・sessionに責任を持たせたオブジェクトを任意のタイミングでDBに反映するためにはあえて指示をする必要があります。
一、知っておくべきこと
世の中のサンプルを参考に、適当に思いこみで作るとはまります。
#きちんとドキュメントを読んでから、あるいは動作を検証してから使いましょう
1は、アクセサをあからさまに書き換えたものと書き換えていない物を使用したテストです。
準備用のSQLを見ればわかるように、更新が行われるとログ用テーブルにレコードが追加されます。
結果はアクセサを上書きした物はセレクトした全件が更新されました(想定通り・・・)。
この後次のようなことを確認しようとしたまま力尽きています。
・PROP_という変数を追加することによる影響の確認(無いっぽいと思っている)
・commonsのBeanUtils#copyPropertiesを使用した場合の動作(関連を持ったhibernateの値オブジェクトとplaneなPOJOで実施)の確認(名前が一致した物のみを呼ぶはずなので、理想的に動作すると思っている)。
2は、面倒な部分を手抜きしたいと思って作ったへぼいツールです。
・middlegenでデータベースをリバースする際にmiddlegenの設定ファイルにテーブルを列挙するのが面倒なので、スキーマレベルでhbmを自動生成する
・価オブジェクトをコピーするためのPOJOをテーブルから自動生成する
・POJOをActionScriptで扱うためのASをテーブルから自動生成する
hbmの自動生成は、関連は無視されます。また型も基本的にプリミティブ型を選択します(hibernateの価オブジェクトにあるプリミティブ型プロパティにDBNullを何も考えずにセットしようとすると例外が発生しますよー)。
hbm/POJO/AS共に型はColumn.javaで決めていますので、好きにカスタマイズしてください(使う人がいた場合ですが。使用方法はbuild.xmlとソースコードを見てください。スキーマはカンマ区切りで複数指定できます)。
Oracle/PostgreSQL/MySqlに対応してるつもりですが、Oracle(9i)とPostgreSQL(8.0)しか試していません(テストコードは一つも書いていません・・)。
多数の方からそれはおかしいという指摘をいただきました。
特にkoichikさんは私の代わりに様々な検証を行ってくださり、そのおかげでやっとhibernateの癖
のいくつか知ることが出来ました(いや、ドキュメントには書いてあるんでしょうが)。
納得がいかないと頑張っていたシチュエーション4(同一Transaction内でセレクトした全てのオブジェクトをTransactionコミット時に勝手に更新)についてもhibernateの使用方法、癖を理解していなかったために陥った誤った認識でした(余裕が出来てコードを見たとたんにへこんだ)。
hibernateの仕様を理解して使用する分にはhibrenateに問題はありません。
#ただ癖がいろいろあることは確かですが。
一、知っておくべきこと
シチュエーション1で、関連の設定を削除しましたが関連の設定を削除してもなお、表示用には本当のPOJOに値をコピーすべきです(POJOのひな形作成をテーブルから自動で行うantタスクを作りました、一番下にはっつけてあります)。
シチュエーション4という誤った思いこみをした原因はここにありました。
middlegenで生成したhbmをhibernate-synchronizerでJavaコード生成すると4つのJavaのファイルができます。
そのうちのTableと同じ名前のクラスはコンストラクタのみで構成されており、かつコンストラクタは「ここからここはさわるな」的なコメントで囲まれています。当然のようにさわってはいけない領域の外に継承元のクラスにあるアクセサメソッドを上書きしてしまいました。
koichikさんの検証にもあるとおり、Transaction内でセレクトしたオブジェクトが更新される条件は二つあります。
1.セレクトしたオブジェクトの価を変更した場合
2.セレクトしたオブジェクトの価が変わったと判断された場合
もうおわかりでしょう。1と2は同一の状態です。
hibernateはセレクトした時点でのデータを保存し、Tranasctionが終了した時点でのデータと比較して更新すべきオブジェクトを確認しています。
そのデータの比較に使用されるのがTableと同じ名前のクラスのアクセサです(つまり継承元のクラスのアクセサ)。
#データの比較をアクセサ経由でなくプロパティで行わせることも設定で可能なようです
一、知っておくべきこと
hibernateのセッションは、ただのデータベースセッションとして認識してはいけません。
hibernateは単なるO/RマッピングツールではなくJavaのオブジェクト永続化機構として見るべきです。
hibernateのセッションオブジェクトはDBのプロキシとして動作します。
セレクトしたオブジェクトについても、新規に作成してsessionにsaveしたオブジェクトについてもsessionが責任を持ちます。
・sessionに一度責任を持たせたオブジェクトをsessionから解放するにはあえて指示する必要があります。
・sessionに責任を持たせたオブジェクトを任意のタイミングでDBに反映するためにはあえて指示をする必要があります。
一、知っておくべきこと
世の中のサンプルを参考に、適当に思いこみで作るとはまります。
#きちんとドキュメントを読んでから、あるいは動作を検証してから使いましょう
ということで、一応成果物をはっつけます。
1.アクセサが原因であることを知った後に頑張って検証しようとした形跡(hibernate_test.tar.gz)
2.データベースのテーブルからhbm・POJO・POJOのASを生成するantタスク(RevDB-0.1.tar.gz)
1は、アクセサをあからさまに書き換えたものと書き換えていない物を使用したテストです。
準備用のSQLを見ればわかるように、更新が行われるとログ用テーブルにレコードが追加されます。
結果はアクセサを上書きした物はセレクトした全件が更新されました(想定通り・・・)。
この後次のようなことを確認しようとしたまま力尽きています。
・PROP_という変数を追加することによる影響の確認(無いっぽいと思っている)
・commonsのBeanUtils#copyPropertiesを使用した場合の動作(関連を持ったhibernateの値オブジェクトとplaneなPOJOで実施)の確認(名前が一致した物のみを呼ぶはずなので、理想的に動作すると思っている)。
2は、面倒な部分を手抜きしたいと思って作ったへぼいツールです。
・middlegenでデータベースをリバースする際にmiddlegenの設定ファイルにテーブルを列挙するのが面倒なので、スキーマレベルでhbmを自動生成する
・価オブジェクトをコピーするためのPOJOをテーブルから自動生成する
・POJOをActionScriptで扱うためのASをテーブルから自動生成する
hbmの自動生成は、関連は無視されます。また型も基本的にプリミティブ型を選択します(hibernateの価オブジェクトにあるプリミティブ型プロパティにDBNullを何も考えずにセットしようとすると例外が発生しますよー)。
hbm/POJO/AS共に型はColumn.javaで決めていますので、好きにカスタマイズしてください(使う人がいた場合ですが。使用方法はbuild.xmlとソースコードを見てください。スキーマはカンマ区切りで複数指定できます)。
Oracle/PostgreSQL/MySqlに対応してるつもりですが、Oracle(9i)とPostgreSQL(8.0)しか試していません(テストコードは一つも書いていません・・)。
Comments
[2005年10月24日(月) 23:29]
たこはち
Hibernate自体「そういうものなのだ」と特に深く考えず利用し製造していました。記事、若干参考になりました。
