【问题标题】:Hibernate many-to-many lazy initialization exceptionHibernate 多对多延迟初始化异常
【发布时间】:2016-05-14 20:31:03
【问题描述】:

我是 JEE 的新手,最近开始学习 Spring 和 Hibernate。我正在尝试开发 RESTful 服务来跟踪带有类别的项目。我有多对多关联(一个项目可以有很多类别,一个类别可以有很多项目),三个表:项目、类别和连接表 item_category。

我正在使用 MySQL 服务器、Spring Boot 1.3.1 和 Hibernate 4.3

我现在要做的是获取带有类别的项目列表和带有项目列表的类别。我为此使用 API 编写了整个应用程序,并以 LazyInitializationException 告终。我尝试了很多方法,但没有帮助。 (我可以设置获取类型 EAGER 但这不是解决方案)。

例如,这是列出所有项目的 API:GET /api/item

这是输出:(不是预期的!):

原因:org.hibernate.LazyInitializationException: failed to lazily >初始化角色集合:com.sk.itemlist.domain.Item.categories,无法初始化代理 - 没有会话 在 org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final] 在 org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final] 在 org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:155) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final] 在 org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:160) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final] 在 com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:101) ~[jackson-databind-2.6.5.jar:2.6.5] 在 com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:24) ~[jackson-databind-2.6.5.jar:2.6.5] 在 com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:693) ~[jackson-databind-2.6.5.jar:2.6.5] 在 com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:675) ~[jackson-databind-2.6.5.jar:2.6.5]

如果您尝试获取所有类别 GET /api/category 或按 id GET /api/category/1 的类别,则会出现同样的错误

这是我的问题:

  1. 如何摆脱 LazyInitializationException?如何配置休眠以重新打开会话?还是应该在 DAO 层初始化集合?
  2. 我阅读了有关 DTO 模式的信息,但我不完全了解它是什么,我应该在这里深入挖掘吗?
  3. 我在尝试将数据插入项目时发现了问题。它只插入项目表,连接表和类别为空。我手动将数据添加到数据库中进行测试
  4. 您对整个应用的感觉如何?我可以在这里改进什么或应该避免什么(如果有的话)

最后,我在这里上传了完整的项目:https://gitlab.com/sksh/ItemList.git
在资源中,您可以找到包含一些随机数据的数据库转储。使用有效的数据库凭据更新 application.properties。

【问题讨论】:

  • public Category findByKey(String key) 中的CategoryDaoImpl.java 是您尝试调用的导致您出现此异常的方法吗?
  • @Rdx 它把它扔到任何地方,findById,listAll 等等。自从我在 Category 中添加项目列表后,它就开始抛出了。
  • GET /api/category throws org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.sk.itemlist.domain.Category.items, 无法初始化代理 - 没有会话,反之亦然如果我尝试获取所有项目(GET /api/item),反之亦然,但在这种情况下,它无法初始化类别

标签: mysql hibernate spring-boot many-to-many lazy-initialization


【解决方案1】:

会发生什么:

  • 您要求 hibernate 获取一些项目
  • Hibernate 带来它们,但不带来项目类别的信息。
  • 当您在数据库会话工作完成后(在 CollectionSerializer 中)尝试访问这些类别时,您会遇到该异常
  • 您需要让 hibernate 连同项目一起带上类别,这样您就可以在会话结束后使用 then(迭代、列表或其他)。

你应该在 DAO 级别使用类似的东西..

// fetch a Criteria reference and use join fetching
 Criteria c = currentSession().createCriteria(Item.class);
 c.setFetchMode("categories", FetchMode.JOIN);
 c.add(Restrictions.eq("id", id));
 Item result = (Item)c.uniqueResult();
 return result;    

还有其他方式,比如在Item中声明

@ManyToMany(fetch=FetchType.EAGER) 
private Set<Category> categories = new HashSet<>();

但这可能会导致性能问题

【讨论】:

  • 我使用您的建议更改了 ItemDaoImpl 中的 findById 方法,现在得到了新的异常:org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: failed to lazily initialize a collection of role: com.sk.itemlist.domain.Category.items, could not initialize proxy - no Session (through reference chain: com.sk.itemlist.domain.Item["categories"]-&gt;org.hibernate.collection.internal.PersistentSet[0]-&gt;com.sk.itemlist.domain.Category["itemList"]);
  • 现在您在 Category 透视图中遇到了同样的问题。您的序列化程序将尝试编写项目列表。每个项目都有一个类别列表。每个类别都有一个项目列表。依此类推..您需要决定在哪里切断在您的表示中获取的引用。杰克逊不会自动执行此操作,您必须执行一些操作。我通常做的事情:我自己实现了要在 API 中返回的信息,方法是使用由 jackson 实际序列化的另一组 DTO,因此我可以控制何时应在会话之外访问集合字段
  • 那么我应该使用包含所有需要信息的 dto 对象而不是实体对象吗?
  • 这是我的建议。否则告诉杰克逊(不知道如何)何时读取 Category 的项目列表。
猜你喜欢
  • 2016-06-16
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 2012-07-27
  • 2014-03-21
  • 2012-08-01
相关资源
最近更新 更多