gpt4 book ai didi

java - Hibernate "failed to lazily initialize a collection"运行时错误

转载 作者:行者123 更新时间:2023-12-02 09:06:54 25 4
gpt4 key购买 nike

这个问题已被问过很多次,但我仍然找不到适合我的用例的解决方案:

  1. 我有一个使用 Hibernate 5.x 的 Struts2 应用程序。

  2. 该应用程序是“通讯录应用程序”。它有两个实体:“联系人”,可以有零个或多个“注释”。

  3. 以下是我获取联系人的方式:

    @Override
    public List<Contact> getContacts() {
    //Note: Hibernate 5++ supports Java try-with-resource blocks
    try (Session session = HibernateUtil.openSession()) {
    List<Contact> contacts = session.createQuery("FROM Contact").list();
    return contacts;
    ...
  4. 效果很好。直到我尝试这样的事情:

    ObjectMapper mapper = new ObjectMapper();
    jsonString = mapper.writeValueAsString(contacts);

错误:

16:05:16.174 [http-nio-8080-exec-2] DEBUG org.apache.struts2.dispatcher.Dispatcher - Dispatcher serviceAction failed
com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.example.contactsapp.models.Contact.notes, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.example.contactsapp.models.Contact["notes"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394) ~[jackson-databind-2.10.0.jar:2.10.0]
...
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:4094) ~[jackson-databind-2.10.0.jar:2.10.0]
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3404) ~[jackson-databind-2.10.0.jar:2.10.0]
at com.example.contactsapp.actions.ContactsAction.getContacts(ContactsAction.java:36) ~[classes/:?]
...

可能的解决方案

  1. 不想想要更改为FetchType.Eager

  2. 由于我没有使用 Spring,因此无法使用 @TransactionalOpenSessionInView。但如果有仅限 Hibernate 的等效项,我会很高兴。

  3. 这些是我尝试过的方法(主要基于 How to solve the “failed to lazily initialize a collection of role” Hibernate exception ):

    @Override
    public List<Contact> getContactsFetchAll() {
    //Note: Hibernate 5++ supports Java try-with-resource blocks
    try (Session session = HibernateUtil.openSession()) {
    // Jackson mapper.writeValueAsString() => "failed to lazily initialize a collection"
    // List<Contact> contacts = session.createQuery("FROM Contact").list();

    // Plan A: Causes same "failed to lazily initialize a collection" runtime error
    // List<Contact> contacts = session.createQuery("FROM Contact").list();
    // Hibernate.initialize(contacts);

    // Plan B: Still no-go: returns [] empty set
    // List<Contact> contacts = session.createQuery("SELECT c FROM Contact c JOIN FETCH c.notes n").list();

    // Plan C: Same: "failed to lazily initialize a collection of role..."
    // Query query = session.createQuery("FROM Contact");
    // Hibernate.initialize(query);
    // List<Contact> contacts = query.list();

    // Plan D: Same: "ERROR: failed to lazily initialize a collection of role"
    // List<Contact> contacts = session.createQuery("FROM Contact").list();
    // for (Contact c : contacts) {
    // Set<Note> n = c.getNotes();
    // }
    return contacts;
    }
    }

问:有什么建议吗?

问:您需要任何其他信息吗?

<小时/>

我做了更多研究。

显然,在这个特定场景中,Hibernate 根本不执行“连接”。

相反:

  1. 它执行“选择”来获取父级。
  2. 如果您尝试从任何子级中读取某些内容,那么它会执行另一个“选择”来获取子级。一个“选择”给 parent ,第二个“选择”给 child 。
  3. 如果实体配置为“急切获取”,则它总是预先执行所有选择。
  4. 对于“延迟获取”,您必须在关闭 session 之前尝试读取子项(从而触发第二个选择)。否则,如果您在 session 关闭后尝试读取子数据,则会收到“无法延迟初始化集合”的信息。
  5. 左连接在这种情况下不起作用:数据库返回的结果集与实体不匹配。为了使其工作,我必须一次读取一行结果集,并手动构建实体。
  6. 我仍在寻找一种方法让“Join Fetch”在我的场景中发挥作用...

最佳答案

如果您在实体配置中使用延迟初始化进行 OneToMany 映射,并且在某些情况下您希望急切地获取集合。我认为您可以使用 @NamedQuery 在单个查询中获取列表(在您的情况下为 Left Join)。

关于java - Hibernate "failed to lazily initialize a collection"运行时错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59743685/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com