Re: hibernateを利用してはいけない5つのシチュエーション
通りすがりさんから頂いたコメント.
「実はUserTypeのequalsメソッドあたりの実装をミスしてる」に一票
ふむ.もし Hibernate が永続オブジェクトが変更されているかチェックするのに永続クラスの equals()
を使っていて,でもでもそいつの実装がヘボヘボだとなにも変更されていない永続オブジェクトを勘違いして UPDATE しちゃうかもしれない,というわけですか.
とりあえず試してみましょうか.
せっかくなので,永続クラスに埋め込みオブジェクトも使ってみましょう.
Model
には firstName
と lastName
という二つのプロパティがあります.
このプロパティを持つ FullName
という埋め込みクラスを用意しましょう.
package hoge; public class FullName { private String firstName; private String lastName; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public boolean equals(Object o) { return false; } }
見ての通り,こいつの equals()
は常に false
を返します.
そして永続クラス Model
はこいつを使います.
package hoge; public class Model { private int id = -1; private FullName fullName; private Magazine magazine; public int getId() { return id; } public void setId(int id) { this.id = id; } public FullName getFullName() { return fullName; } public void setFullName(FullName fullName) { this.fullName = fullName; } public Magazine getMagazine() { return magazine; } public void setMagazine(Magazine magazine) { this.magazine = magazine; } public boolean equals(Object obj) { return false; } public String toString() { return fullName.getFirstName() + " " + fullName.getLastName() + ", " + magazine; } }
こっちの equals()
も無条件に false()
を返します.
んで,テスト用のメソッド.
public void testHibernateTransaction() throws Exception { Configuration config = new Configuration(); SessionFactory factory = config.configure("hibernate3.cfg.xml").buildSessionFactory(); Session session = factory.openSession(); Transaction tx = session.beginTransaction(); Magazine magazine = (Magazine) session.get(Magazine.class, new Integer(1)); Model model = (Model) magazine.getModels().iterator().next(); System.out.println(model); tx.commit(); }
今度はなにも変更していません.
Magazine
を取得して,関連をたどることで Model
を取得します.
さて Model
は更新されるでしょうか?
発行された SQL.
Hibernate: select magazine0_.id as id0_, magazine0_.title as title1_0_ from Magazine magazine0_ where magazine0_.id=? Hibernate: select models0_.contract as contract1_, models0_.id as id1_, models0_.id as id0_, models0_.firstName as firstName0_0_, models0_.lastName as lastName0_0_, models0_.contract as contract0_0_ from Model models0_ where models0_.contract=?
そんなわけで (どんなわけで?),更新されませんでした.(^^;
Hibernate は RDB から取得したデータをセッションに保持しているのですが,それは永続クラスのインスタンスとしてではなく,ResultSet
から取得した String
や Integer
などで保持しています.たぶん.Hibernate 2.x ではそうだったはず.
たぶん,Hibernate3 では org.hibernate.engine.PersistentContext
あたり.
なので,永続クラスの equals()
がヘボヘボでも
hibernateでTransactionを使用すると、同一Transaction内でセレクトした全てのオブジェクトをTransactionコミット時に勝手に更新します。
にはならないような気のせいが...
やはり,元記事の著者さんに解説をお願いしたい今日この頃です〜.