我得到org.hibernate.LazyInitializationException: illegal access to loading collection
在我的 JPA 代码中 - 当集合实体也有一个集合时,所有集合都是 EAGER fetch。
有人可以帮我解决这个问题吗?
我已将 JPA 代码中的问题隔离到以下 @Entity
定义:
(注意,我跳过了 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();
}
(如果我明确执行完整的 @JoinTable
,我也会遇到同样的问题,但 Hibernate 似乎在没有它的情况下生成一切正常 - 我很高兴将其排除在外)。
问题是,如果我取消注释 @MyEntity
中的“tags”字段,然后我总是得到以下 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 when field is eager但这似乎是因为 load()
获取实体的惰性版本。我在这里使用“查找”。我注意到,如果我发出 JPA 查询(而不是查找),那么这个问题就会消失。
更新:如果不是find()
,这确实可以正常工作。 ,我使用像 "SELECT b FROM MyOtherEntity b WHERE b.id = :id"
这样的查询。也许find()
确实忽略EAGER
加载中!因此,这可能是 Hibernate 中的一个错误。
更新:我已将其记录为 Hibernate 的错误报告,地址为 https://hibernate.onjira.com/browse/HHH-7476
最佳答案
首先,引用完整的堆栈跟踪很有用:http://pastie.org/4358203
该问题是由您在 MyEntity 的 hashCode() 实现中调用tags.hashCode() 引起的。
当您使用 Hibernate 加载 MyOtherEntity 实例时,它的 MyEntity 集合被初始化。当 MyEntity 添加到 MyOtherEntity 内的 Set 实现时,它的 hashCode() 方法自然会被调用(记住,集合不能包含重复项,hashCode() 是 Java 检查对象相等性的一部分)。然后,MyEntity 的 hashCode() 方法尝试在标签集合上调用 hashCode()。标签集合正在初始化,这会导致您出现此错误。
我认为值得考虑一下 MyEntity 的 hashCode() 实现。您的用例是否真的需要您比较标签集合中所有元素的值以确保对象相等?
有关在 Hibernate 中管理对象相等性的更多信息,以下是有用的资源:
关于java - Hibernate LazyInitializationException on find() 与 EAGER @ElementCollection,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11604370/