DATE : 2007/05/26 (Sat)
Spring Frameworkの org.springframework.orm.hibernate3.HibernateTemplate#load()を使用してオブジェクトを取得した後にそのオブジェクトのメソッドを呼び出すと、org.hibernate.LazyInitializationException という例外が発生してしまいました。
HibernateTemplate#load() は、内部で Session#load()を呼び出しています。Hibernate には遅延読み込みという機能があり、Session#load()から返されるオブジェクトはオブジェクトそのものではなく、そのオブジェクトの内容を(データベースなどから)読み込むオブジェクトが返されます。こうすることで、オブジェクトのプロパティが必要になった時になって初めてデータが読み込まれるので、オブジェクトの生成に時間がかからないわけです。
ところが、そのデータを読み込めるのは Hibernate セッションが開いている間だけです。つまり、Hibernate セッションを閉じた後にプロパティを初めて参照した場合は例外が発生します。それが LazyInitializationException です。
通常は、Hibernate セッションの管理は開発者が手動で行わなければなりませんが、HibernateTemplate は Hibernate セッションを自動的に管理してくれるので、セッションの管理を気にする必要はなくなります。
(;^ω^)ところが、ここに落とし穴があって、HibernateTemplate#load() も例に漏れず、内部で Hibernate セッションが閉じられていました。なので、Hibernate セッション外で HibernateTemplate#load() を使って読み込んだオブジェクトのプロパティを参照すると、LazyInitializationException が発生します。
そこで、HibernateTemplate#get() に処理を変えました。Session#load() と違い、Session#get() はオブジェクトそのものを読み込みます。そのため、Hibernate セッションが閉じられた後でもオブジェクトのプロパティを参照できます。
(;^ω^)Session#load() と Session#get() は一見おなじような機能なので、適当に load() を利用していたのが間違いでした。同じような機能が複数ある場合は、違いをよく確認しないといけませんね。
参考文献
- Hibernate Reference Documentation - Chapter 10. Working with objects
- /spring/src/org/springframework/orm/hibernate3/HibernateTemplate.java