3

コレクションエンティティにもコレクションがある場合、JPAコードを取得org.hibernate.LazyInitializationException: illegal access to loading collectionしています-すべてのコレクションはEAGERフェッチです.

誰かがこれを修正するのを手伝ってくれませんか?

JPA コードの問題を次の@Entity定義に切り分けました。

(コードを短くするために package および import ステートメントをスキップしていることに注意してください。フィールドに getter/setter があることを意味する @Data や、通常の try/catch close() を実行する @Cleanup など、いくつかの Lombok アノテーションが使用されています。ダンス)

@Entity
@Data
public class MyEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

//    @ElementCollection(fetch = FetchType.EAGER)
//    private Set<String> tags = Sets.newTreeSet();
}

@Entity
@Data
public class MyOtherEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToMany(fetch = FetchType.EAGER)
    private Set<MyEntity> entities = Sets.newHashSet();
}

(明示的に full@JoinTableを実行した場合も同じ問題が発生しますが、Hibernate はそれがなくてもすべて正常に生成されるようです。省略しても問題ありません)。

問題は、の「タグ」フィールドのコメントを外すと、@MyEntity常に次のようになることですPersistenceException

Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.LazyInitializationException: illegal access to loading collection
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
    at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:828)
    at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:781)

以下は、問題を例示する短いアプリケーションです。

public class JpaQuestion {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        properties.put("hibernate.connection.driver_class", "org.apache.derby.jdbc.EmbeddedDriver");
        properties.put("hibernate.connection.url", "jdbc:derby:playground;create=true");
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("PlaygroundPU", properties);

        populate(emf);

        @Cleanup("close") EntityManager em = emf.createEntityManager();
        MyOtherEntity other = em.find(MyOtherEntity.class, 1L);
        System.out.println(other != null ? other.toString() : "null");
    }

    public static void populate(EntityManagerFactory emf) {
        @Cleanup("close") EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        MyEntity a = new MyEntity();
        em.persist(a);
        MyOtherEntity other = new MyOtherEntity();
        other.getEntities().add(a);
        em.persist(other);
        em.getTransaction().commit();
    }
}

更新:フィールドが熱心な場合の LazyInitializationExceptionについては知っていますload()が、エンティティの遅延バージョンを取得しているためと思われます。ここでは「検索」を使用しています。(find ではなく) JPA クエリを発行すると、この問題が解決することに気付きました。

find()更新: の代わりに のようなクエリを使用すると、これは実際にうまく機能し"SELECT b FROM MyOtherEntity b WHERE b.id = :id"ます。たぶんfind()本当にEAGER読み込みを無視します! したがって、これはおそらく Hibernate のバグです。

更新: https://hibernate.onjira.com/browse/HHH-7476でこれを Hibernate のバグ レポートとして記録しました。

4

4 に答える 4

12

まず、完全なスタックトレースを参照すると便利です:http://pastie.org/4358203

この問題は、MyEntityのhashCode()実装内のtags.hashCode()の呼び出しが原因で発生しています。

Hibernateを使用してMyOtherEntityインスタンスをロードすると、MyEntityのコレクションが初期化されます。MyEntityがMyOtherEntity内のSet実装に追加されると、そのhashCode()メソッドが自然に呼び出されます(セットに重複を含めることはできません。hashCode()はJavaがオブジェクトの同等性をチェックする方法の一部です)。次に、MyEntityのhashCode()メソッドは、タグコレクションでhashCode()を呼び出そうとします。タグコレクションは初期化中です。そのため、このエラーが発生します。

MyEntityのhashCode()実装について考える価値があると思います。あなたのユースケースでは、オブジェクトの同等性を確認するために、タグコレクション内のすべての要素の値を比較する必要が本当にありますか?

Hibernateでのオブジェクトの同等性の管理の詳細については、以下が役立つリソースです。

https://community.jboss.org/wiki/EqualsAndHashCode

于 2012-07-30T12:05:52.287 に答える
1

LazyInitializationException – セッション コンテキスト外のフェッチされていないデータへのアクセスを示します。たとえば、セッションが閉じられた後に、初期化されていないプロキシまたはコレクションがアクセスされた場合です。

あなたが試してみたいかもしれないいくつかのこと:

削除@Cleanup-LazyInitializationException通常は、プロキシがフィールドにアクセスしようとしたときに Hibernate セッションが閉じられたことを意味するため、これらの@Cleanup注釈なしで試してください。私はそれらを自分で使用したことはありませんが、ドキュメントによると、変数宣言は.close()「スコープの終わり」を呼び出すことでクリーンアップされます。

ダブルチェック構成FetchType.EAGER-両方の関連付けについて宣言しているように、まだ奇妙です。これらのオプションが実際に使用されることを確認しましたか? 構成が少し難しい場合があることは承知しています。

PersistenceContextTypePersistenceContextType.EXTENDED - あなたはあなたのために設定しようとするかもしれませんEntityManager(デフォルトだと思いますTRANSACTIONが、間違っているかもしれませんが、確認したいかもしれません)。

トランザクション スコープの永続コンテキストの場合、エンティティは分離されます。つまり、エンティティは管理されなくなります。拡張永続コンテキストの場合、エンティティは引き続き管理されます。

「LazyInitializationException を克服する」 wiki エントリを既にご存知でしょうか。

于 2012-07-23T14:09:29.203 に答える
0

このエラーは、hibernate がオブジェクトを初期化しようとしてエラーが発生した場合に表示されます。

エラーの可能性

  1. Hash Code And Equals が適切に実装されていない
  2. 遅延オブジェクトは暗号化されることが期待されていますが、データベースでは適切に暗号化されていません
  3. 休止状態のセッション コンテキストの外にいます。
于 2013-11-17T07:31:31.747 に答える