2009-02-23 10 views
47

私は遅延初期化を使用したい顧客のためのプロジェクトに取り組んでいます。 デフォルトのレイジーローディングモードでクラスをマッピングするとき、それらは常に「遅延初期化例外」を取得します。JPAとHibernateを使用するときにLazyInitializationExceptionを解決する方法

@JoinTable(name = "join_profilo_funzionalita", joinColumns = {@JoinColumn(name = "profilo_id", referencedColumnName = "profilo_id")}, inverseJoinColumns = {@JoinColumn(name = "funzionalita_id", referencedColumnName = "funzionalita_id")}) 
//@ManyToMany(fetch=FetchType.EAGER) - no exceptions if uncommented 
@ManyToMany 
private Collection<Funzionalita> funzionalitaIdCollection; 

このエラーを回避するためにJPAクラスを使用する標準パターンはありますか?

スニペットをご利用いただきありがとうございます。

答えて

5

OpenSessionInViewは、この問題を処理する1つのパターンです。ここではいくつかの情報:

http://www.hibernate.org/43.html

あなたはこのパターンを実装するときに注意が必要と意味を理解したいと思います。ビュー内の遅延結合をナビゲートするたびに、データをロードする別のSQL問合せが起動します。これらのSQLクエリの数とサイズが小さいユースケースの場合、これは重要ではありません。少なくとも、データをロードするためにHibernateがバックグラウンドでどのようなクエリを「魔法のように」実行しているかを見ることができるように、ロギング設定を調整してください。

また、作成しているアプリケーションの種類も考慮してください。リモート処理(Webサービスなし、AJAXベースのWebクライアントなし)を扱っていない場合、OSIVはうまく動作するかもしれません。しかし、リモートシリアライザがオブジェクトグラフ全体を歩き始めると、不思議な数のSQLクエリがトリガされ、DBとアプリケーションサーバーが壊れる可能性があります。

+0

サーバーに負荷がかかると見える場合は、開いているセッションを表示しないでください。この答えは、その方向の警告を使用する可能性があります。 – iwein

+1

私はリンクがパターンの意味を説明するのに十分であると思ったが、ちょっとした警告を追加した。 :) –

7

LazyInitializationExceptionは、休止状態のセッションが閉じられた後、またはオブジェクトがセッションから切り離された後でコレクションを呼び出すことを意味します。

セッションを休止状態にするためにオブジェクトを再接続するか、コレクションを呼び出す場所を変更するか、セッションが終了する境界を上位レイヤに移動する必要があります。

+12

いいですが、どうですか? –

+2

まさに、我々はWHATの部分を得ました。どのように質問です! – Nikhil

16

プリフェッチの特性に多くの方法がありますので、セッションが閉じられた後、彼らはあります

  1. コール適切なゲッターは。フィールドがBeanにフェッチされた後、セッションが閉じられた後にそこにあります。
  2. EJBQLクエリでフィールドを初期化する場合は、JOIN FETCHというキーワードを探します。
  3. これをサポートするHibernateバージョンを使用している場合は、AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANSを有効にします。あなたはこれらのソリューションをしようとすると、

いくつかの問題が発生する可能性があります

  1. ゲッターの呼び出しは、JITコンパイラによって離れて最適化することができる(時には、これは時間がかかります)。
  2. JOIN FETCHにしようとしているエンティティは、Listを含む複数の「多数の」関係によってリンクされている可能性があります。この場合、結果のクエリはあいまいな結果を返し、Hibernateは単一のクエリでデータを取得することを拒否します。
  3. すでに1つがありますinteresting bug related to AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANSです。そして、休止状態の人たちが言うように、より多くがあるでしょう:注:これはトランザクションの外で起こり、安全ではありません。慎重に使用してください。あなたは主にあなた自身でいます。

最初にJOIN FETCHを試してみることをおすすめします。それがうまくいかない場合は、ゲッターのアプローチを試してみてください。それがJITコンパイラによって実行時に乱れた場合は、結果をpublic static volatile Objectに代入します。

または休止状態を使用して停止...

+0

ポイント(3)は、バグがバージョン4.1.7以降でクローズされていることに注意する価値があります。執筆時点では、まだ開いている問題はhttps://hibernate.atlassian.net/browse/HHH-8782です。 –

+2

"またはHibernateの使用を停止..." ... amen。 –

4

コレクションを使用していて、その後、遅延ロードでそれを初期化し、セッションを閉じる前に、そのコレクションを使用します。それ以降にセッションが終了した場合は、lazyがデフォルトでtryであるため、lazyinitializeExceptionを取得します。

60

にHibernate 4.1.6が最終的にこの問題を解決:https://hibernate.atlassian.net/browse/HHH-7457

あなたは休止状態-プロパティhibernate.enable_lazy_load_no_transを設定する必要があります=真

をここでは春にそれを行う方法は次のとおりです。

<bean id="entityManagerFactory" 
     class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="myDataSource"/> 
    <property name="packagesToScan" value="com.mycompany.somepackage"/> 
    <property name="jpaVendorAdapter" ref="hibernateVendorAdapter"/> 
    <property name="jpaDialect" ref="jpaDialect"/> 
    <property name="jpaProperties"> 
     <props> 
      <prop key="hibernate.enable_lazy_load_no_trans">true</prop> 
     </props> 
    </property> 
</bean> 

Voila;これで、Hibernateセッション(永続コンテキスト - 「JPA-speak」の外部)でドメインモデルをナビゲートする際にLazyInitializationExceptionを気にする必要はありません。

+3

私はこれを見ることを喜んだのですか?どうもありがとう。 – Oversteer

+1

このプロパティが正確に行うことを回答に追加できますか?この実装は、データの一貫性やパフォーマンスに深刻な影響を与える可能性があります。おそらく両方。 – iwein

+1

このオプションを使用すると、トランザクション外で遅延結合をロードします。つまり、データが親エンティティのものと一致しない可能性があります。しかし、それはSpringのOpenEntityManagerInViewFilterを使うよりも悪くはありません。これはトランザクション外のものも読み込みます。私はフィールドベースのマッピングを使用しており、JITが生成されたプロキシを混乱させることは経験していません。 – andreak

14

Hibernate 4.1.7より前のバージョンは使用しないでください。接続が漏れてしまいます。 https://hibernate.onjira.com/browse/HHH-7524

+1

これは動作しますが、今は再帰的サイクリングの問題があります。 –

1

Oracle Javaチュートリアルでは、「エンタープライズBeanはトランザクション、共有オブジェクトの同時アクセスを管理するメカニズムをサポートしています」と指摘しています。したがって、Lazy Fetchの問題を処理するために、ステートレスJavaセッションBeanを作成し、メソッドから戻る前に必要なすべてのサブクラスを取得します。これにより、遅延フェッチ例外が回避されます。 Oracleは、これを「セッション・ファサード」のコアJ2EEパターンとも呼んでいます。このパターンは、言及された他のプラクティスのいくつかよりも優れているようです。

2

The best way to solve the LazyInitializationExceptionエンティティクエリでJOIN FETCHディレクティブを使用することです。

EAGER loadingはパフォーマンスに悪いです。

彼らのどちらかが、UIのレンダリング中(オープンセッションのために開いているデータベース接続を必要とするため、使用することはありません

:また、のようなアンチパターンがありますビュー)、または最初の永続コンテキスト(hibernate.enable_lazy_load_no_trans)の外部にフェッチされるすべての遅延結合に対してデータベース接続が必要です。

エンティティが必要ない場合もありますが、DTO投影法はさらに優れています。 エンティティを変更する必要がある場合にのみ、エンティティをフェッチする必要があります。読み取り専用トランザクションの場合は、DTO projections are better