【问题标题】:Spring Hibernate FetchType LazyInitializationException even when not calling association即使不调用关联,Spring Hibernate FetchType LazyInitializationException
【发布时间】:2017-11-21 13:13:18
【问题描述】:

我刚刚开始了解 FetchType Lazy 和 Eager。我理解其中的区别,但即使我设置为 Lazy,它仍然以某种方式尝试获取相关数据。

关系:1 人:许多电话

查看的研究尝试和教程:

https://www.mkyong.com/hibernate/hibernate-one-to-many-relationship-example-annotation/ http://howtodoinjava.com/hibernate/lazy-loading-in-hibernate/ https://howtoprogramwithjava.com/hibernate-eager-vs-lazy-fetch-type/

我知道要获取相关数据,我需要在 session() 中执行它所以对于我的特定示例在我的 Dao 中,我需要这样的东西

  List<Person> persons = criteria.list();

    for(Person person : persons){

        Set sets = person.getPhones();

    }
    return persons;

到目前为止正确吗?

但问题是我没有在 Dao、controller..etc 以外的任何地方调用 person.getPhones(),但我得到了 LazyInitializationEception。因为我这辈子似乎无法发现问题所在。

堆栈跟踪

Jun 19, 2017 2:24:01 PM org.apache.catalina.core.StandardWrapperValve invoke
 SEVERE: Servlet.service() for servlet [app-dispatcher] in context with path 
 [/uni-starter-onetomany] threw exception [Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.app.person.Person.phones, could not initialize proxy - no Session] with root cause
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.app.person.Person.phones, could not initialize proxy - no Session

Person.class

@Entity
@Table(name="person")
@Component
public class Person {

@Id
@GeneratedValue
private int person_id;

private String name;

private String age;

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "person")
private Set<Phone> phones;

//  Getter and setters

// ToString method by field name not by method

Phone.class

@Entity
@Table(name="phone")
@Component
public class Phone {

@Id
@GeneratedValue
private int phone_id;

private String type;

private String phone;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="person_person_id")
private Person person;

//  Getter and setters

PersonDao

    @Repository
 @Transactional
 @Component("personDao")
 public class PersonDao {

@Autowired
private SessionFactory sessionFactory;

public Session session(){
    return sessionFactory.getCurrentSession();
}

public List<Person> getPersonList(){
    Criteria criteria = session().createCriteria(Person.class);

    List<Person> persons = criteria.list();

    //  for(Person person : persons){
    //
    //    Set sets = person.getPhones();
    //
    //  }

    return persons;
}


public void saveOrUpdate(Person person){
    session().saveOrUpdate(person);
}

}

控制器

    // Get list
@RequestMapping(path="/list", method = RequestMethod.GET, produces="application/json")
@ResponseBody
public Map<String, Object> getListPerson(){

    Map<String, Object> data = new HashMap<String, Object>();

    List<Person> persons = personDao.getPersonList();       

    data.put("results", persons);

    System.out.println(persons);

    return data;
}

问题

  1. 只要我不在会话中调用 person.getPhones() 就应该只返回人?如果是这样,我得到 LazyInitializationException 的问题可能是什么?

  2. 我还看到有人在 Dao 类中使用 setFetchMode() FetchMode.JOIN 例如 Hibernate Criteria Join with 3 Tables 也许这可能是主观的,但更好的做法是什么?任何性能问题?

非常感谢任何想法、链接或文章...

更新 感谢 Abassa 从 Person.class 中的 toString 中删除 Phone 解决了这个问题。但我只是意识到,由于杰克逊,在序列化过程中它会尝试获取 Phone ojbect.... 有解决方法吗?

Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: failed to lazily initialize a collection of role: com.app.person.Person.phones, could not initialize proxy - no Session

【问题讨论】:

  • 您是否在 Person 类的 toString 方法中打印电话属性?
  • Fetchmode 在您需要指定必须如何获取关系时很有用。通过加入或选择 FecthMode。请参阅文档:docs.jboss.org/hibernate/orm/4.1/javadocs/org/hibernate/… 根据您的数据库模型,选择其中之一可能会导致性能问题。
  • @AbassA 是的,我必须亲自到场
  • 因此,当您调用 System.out.println(persons); 时,它会为列表中的每个人调用 toString 方法,并且由于您尝试在 Person 类的 toString 方法中打印电话,因此您会得到 LazyInitializationException。所以只需从 toString 中删除电话属性。它应该工作
  • @Abassa 是的,但是当你的 toString 方法返回像 return "Person [person_id=" + person_id ..... , phones=" + phones + "]"; 这样的字段时,我不调用 getPhone 方法不应该只返回 null 吗?

标签: java hibernate


【解决方案1】:

从 Person 类的 toString 方法中删除电话字段。

当你打电话时:

System.out.println(persons);

您尝试访问电话字段,因为 println 为列表中的每个人调用了 toString 方法,因此您得到了 LazyInitializationException。

【讨论】:

    猜你喜欢
    • 2014-07-11
    • 1970-01-01
    • 1970-01-01
    • 2011-12-21
    • 1970-01-01
    • 1970-01-01
    • 2017-02-23
    • 2012-11-19
    相关资源
    最近更新 更多