java 使用 EAGER @ElementCollection 在 find() 上休眠 LazyInitializationException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11604370/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:45:23  来源:igfitidea点击:

Hibernate LazyInitializationException on find() with EAGER @ElementCollection

javahibernatejpapersistence

提问by fommil

I am getting org.hibernate.LazyInitializationException: illegal access to loading collectionin my JPA code - all collections are EAGER fetch - when the collection entity also has a collection.

我正在org.hibernate.LazyInitializationException: illegal access to loading collection输入我的 JPA 代码 - 所有集合都是 EAGER fetch - 当集合实体也有一个集合时。

Could somebody please help me to fix this?

有人可以帮我解决这个问题吗?

I have isolated a problem in my JPA code to the following @Entitydefinitions:

我已将 JPA 代码中的问题隔离为以下@Entity定义:

(note, I'm skipping the package and import statements to shorten the code. Some Lombok annotations are used, such as @Data to mean that the field has a getter/setter and @Cleanup to do the usual try/catch close() dance)

(注意,我跳过 package 和 import 语句以缩短代码。使用了一些 Lombok 注释,例如 @Data 表示该字段有一个 getter/setter 和 @Cleanup 来执行通常的 try/catch close()舞蹈)

@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();
}

(I also get the same problem if I explicitly do a full @JoinTable, but Hibernate seems to generate everything fine without it - I'm happy leaving it out).

(如果我明确执行 full @JoinTable,我也会遇到同样的问题,但 Hibernate 似乎在没有它的情况下可以正常生成所有内容 - 我很高兴将其省略)。

The problem is that if I uncomment the "tags" field in @MyEntity, then I always get the following PersistenceException

问题是,如果我取消注释中的“标签”字段@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)

The following is a short application which exemplifies the problem:

下面是一个简短的应用程序,它举例说明了这个问题:

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();
    }
}

UPDATE: I know about LazyInitializationException when field is eagerbut that seems to be because load()grabs a lazy version of the entity. I'm using "find" here. I've noticed that if I issue a JPA query (instead of find), then this problem goes away.

更新:当字段急切时,我知道LazyInitializationException ,但这似乎是因为load()抓取了实体的惰性版本。我在这里使用“查找”。我注意到如果我发出 JPA 查询(而不是查找),那么这个问题就会消失。

UPDATE: This really does work fine if instead of find(), I use a Query like "SELECT b FROM MyOtherEntity b WHERE b.id = :id". Maybe find()really does ignore EAGERloading! Hence this is likely a bug in Hibernate.

更新:如果find()我使用像"SELECT b FROM MyOtherEntity b WHERE b.id = :id". 也许find()真的忽略了EAGER加载!因此,这很可能是 Hibernate 中的一个错误。

UPDATE: I've logged this as a bug report with Hibernate at https://hibernate.onjira.com/browse/HHH-7476

更新:我已将此记录为 Hibernate 的错误报告,网址https://hibernate.onjira.com/browse/HHH-7476

回答by Rob Blake

First of all it is useful to reference the full stack trace: http://pastie.org/4358203

首先,参考完整的堆栈跟踪很有用:http: //pastie.org/4358203

The problem is being caused by your call to tags.hashCode() within the hashCode() implementation of MyEntity.

问题是由您在 MyEntity 的 hashCode() 实现中调用 tags.hashCode() 引起的。

When you use Hibernate to load the MyOtherEntity instance, it's collection of MyEntity is initialised. When a MyEntity is added to the Set implementation within MyOtherEntity, it's hashCode() method is naturally called (sets cannot contain duplicates remember and hashCode() is part of how Java checks for object equality). The hashCode() method of MyEntity then attempts to invoke hashCode() on the tags collection. The tags collection is in the process of being initialised, which leads you to this error.

当您使用 Hibernate 加载 MyOtherEntity 实例时,它的 MyEntity 集合被初始化。当 MyEntity 被添加到 MyOtherEntity 中的 Set 实现时,它的 hashCode() 方法自然会被调用(记住,集合不能包含重复项,hashCode() 是 Java 检查对象相等性的方式的一部分)。MyEntity 的 hashCode() 方法然后尝试对标签集合调用 hashCode() 。标签集合正在初始化过程中,这会导致您出现此错误。

I think it is worth thinking about your hashCode() implementation for MyEntity. Does your use-case really require you to compare the value of the all elements within the tags collection to ensure object equality?

我认为值得考虑 MyEntity 的 hashCode() 实现。您的用例是否真的需要您比较标签集合中所有元素的值以确保对象相等?

For more information on managing object equality in Hibernate, the following is a useful resource:

有关在 Hibernate 中管理对象相等性的更多信息,以下是有用的资源:

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

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

回答by Wolfram

LazyInitializationException – Indicates access to unfetched data outside of a session context. For example, when an uninitialized proxy or collection is accessed after the session was closed.

LazyInitializationException – 表示访问会话上下文之外的未提取数据。例如,在会话关闭后访问未初始化的代理或集合时。

Some things you might want to try:

您可能想尝试的一些事情:

Removed @Cleanup- As a LazyInitializationExceptionusually means that the Hibernate session was closed when a proxy tried to access a field, you should try it without those @Cleanupannotations. I never used them myself, but the docs say that the variable declaration gets cleaned up by calling .close()"the end of your scope".

已删除@Cleanup-LazyInitializationException通常意味着当代理尝试访问字段时 Hibernate 会话已关闭,您应该在没有这些@Cleanup注释的情况下尝试它。我自己从未使用过它们,但文档说通过调用.close()“范围的结尾”来清理变量声明。

Doublecheck configuration- Still odd, as you declare FetchType.EAGERfor both associations. Have you checked that these options really get used? I know that the configuration might sometimes get a little tricky.

双重检查配置- 仍然很奇怪,正如您FetchType.EAGER为两个关联声明的那样。您是否检查过这些选项是否真的被使用过?我知道配置有时可能会有点棘手。

PersistenceContextType- You might want to try to set PersistenceContextType.EXTENDEDfor your EntityManager(I think TRANSACTIONis the default, could be wrong but you might want to try to be sure).

PersistenceContextType- 您可能想尝试PersistenceContextType.EXTENDED为您的设置EntityManager(我认为TRANSACTION是默认设置,可能是错误的,但您可能想尝试确定)。

In the case of a transaction-scoped persistence context, the entities become detached, that is, they are no longer managed. In the case of an extended persistence context, the entities remain managed.

在事务范围持久性上下文的情况下,实体变得分离,即不再管理它们。在扩展持久性上下文的情况下,实体保持受管。

I guess you already know the "LazyInitializationException overcome"wiki entry?

我想您已经知道“克服 LazyInitializationException”维基条目了吗?

回答by dex1304

The problem is that Hibernate ignores fetch = FetchType.EAGER for most queries. Try adding @Fetch(FetchMode.JOIN) to entities.

问题是 Hibernate 忽略了大多数查询的 fetch = FetchType.EAGER。尝试将 @Fetch(FetchMode.JOIN) 添加到实体。

See: https://community.jboss.org/wiki/HibernateFAQ-AdvancedProblems#Hibernate_ignores_my_outerjointrue_or_fetchjoin_setting_and_fetches_an_association_lazily_using_n1_selects

参见:https: //community.jboss.org/wiki/HibernateFAQ-AdvancedProblems#Hibernate_ignores_my_outerjointrue_or_fetchjoin_setting_and_fetches_an_association_lazily_using_n1_selects

回答by Zuned Ahmed

This error Appears when hibernate try to initialize object and some error occur.

当休眠尝试初始化对象并发生某些错误时出现此错误。

Error Can be

错误可以是

  1. Hash Code And Equals Not properly implemented
  2. the lazy object is expected to be encrypted but in db it is not properly encrypted
  3. you are outside the hibernate session context.
  1. 哈希码和等于未正确实现
  2. 惰性对象应该被加密,但在 db 中它没有正确加密
  3. 您在休眠会话上下文之外。