[英]Hibernate infinite loop recursion in many to many relation
I want to create bidirectional student-discipline relation. 我想创建双向的学生-学科关系。 Anything works fine until I've enrolled user to discipline.
在我已将用户注册为纪律人员之前,一切正常。 Now I'm getting infinite recursion.
现在,我得到了无限递归。
Classes looks like this: 类看起来像这样:
//Student.java
@Entity
@Table(name = "students")
public class Student {
@NotNull
@Id
@Column(name = "STUDENT_ID")
private String id;
private String name;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name = "students_disciplines", joinColumns = @JoinColumn(name = "STUDENT_ID"), inverseJoinColumns = @JoinColumn(name = "DISCIPLINE_ID"))
@JsonSerialize(using = NestedDisciplineSetSerializer.class)
private Set<Discipline> disciplines = new HashSet<>();
//Getters, Setters
}
//NestedDisciplineSetSerializer.java
public class NestedDisciplineSetSerializer extends JsonSerializer<Set<Discipline>> {
@Override
public void serialize(Set<Discipline> value, JsonGenerator jgen, SerializerProvider p) throws IOException, JsonProcessingException {
jgen.writeStartArray();
for (Discipline s : value) {
jgen.writeStartObject();
jgen.writeStringField("name", s.getName());
jgen.writeNumberField("id", s.getId());
jgen.writeBooleanField("recommended", s.isRecommended());
jgen.writeEndObject();
}
jgen.writeEndArray();
}
}
//Discipline.java
@Entity`enter code here`
@Table(name = "disciplines")
public class Discipline {
@GeneratedValue(strategy = GenerationType.AUTO)
@Id
@Column(name = "DISCIPLINE_ID")
private int id;
@NotNull
private String name;
@NotNull
private int credits;
private String annotation;
private boolean recommended;
@ManyToMany(mappedBy = "disciplines", fetch = FetchType.EAGER)
@JsonSerialize(using = NestedStudentSetSerializer.class)
private Set<Student> students = new HashSet<>();
//Getters, Setters
}
//NestedStudentSetSerializer.java
public class NestedStudentSetSerializer extends JsonSerializer<Set<Student>> {
@Override
public void serialize(Set<Student> value, JsonGenerator jgen, SerializerProvider p) throws IOException, JsonProcessingException {
jgen.writeStartArray();
for (Student s : value) {
jgen.writeStartObject();
jgen.writeStringField("name", s.getName());
jgen.writeStringField("id", s.getId());
jgen.writeEndObject();
}
jgen.writeEndArray();
}
}
Error appears to be while loading Set after Student s = sDao.findOne(id);
在
Student s = sDao.findOne(id);
之后加载Set时似乎出现错误Student s = sDao.findOne(id);
Tried to search here, but was not able to find right solution. 试图在这里搜索,但找不到正确的解决方案。 Anything made the same result.
一切都取得了相同的结果。
org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:430) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final] at truelecter.practproekt.entity.
org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:430)〜[hibernate-core-5.0.11.Final.jar:5.0.11.Final] at truelecter.practproekt.entity。 Discipline.hashCode (Discipline.java:31) ~[classes/:na] at java.util.HashMap.hash(HashMap.java:338) ~[na:1.8.0_91] at java.util.HashMap.put(HashMap.java:611) ~[na:1.8.0_91] at java.util.HashSet.add(HashSet.java:219) ~[na:1.8.0_91] at java.util.AbstractCollection.addAll(AbstractCollection.java:344) ~[na:1.8.0_91] at org.hibernate.collection.internal.PersistentSet.endRead(PersistentSet.java:327) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final] at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:234) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final] at ... org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:430) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final] at truelecter.practproekt.entity.
Discipline.hashCode (Discipline.java:31)〜[classes /:na]在java.util.HashMap.hash(HashMap.java:338)〜[na:1.8.0_91]在java.util.HashMap.put(HashMap .java:611)〜[na:1.8.0_91] at java.util.HashSet.add(HashSet.java:219)〜[na:1.8.0_91] at java.util.AbstractCollection.addAll(AbstractCollection.java:344 )〜[na:1.8.0_91] at org.hibernate.collection.internal.PersistentSet.endRead(PersistentSet.java:327)〜[hibernate-core-5.0.11.Final.jar:5.0.11.Final] at org .hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:234)〜[hibernate-core-5.0.11.Final.jar:5.0.11.Final] at ... org.hibernate.collection.internal .PersistentSet.hashCode(PersistentSet.java:430)〜[hibernate-core-5.0.11.Final.jar:5.0.11.Final] at truelecter.practproekt.entity。 Student.hashCode (Student.java:29) ~[classes/:na] at java.util.HashMap.hash(HashMap.java:338) ~[na:1.8.0_91] at java.util.HashMap.put(HashMap.java:611) ~[na:1.8.0_91] at java.util.HashSet.add(HashSet.java:219) ~[na:1.8.0_91] at java.util.AbstractCollection.addAll(AbstractCollection.java:344) ~
Student.hashCode (Student.java:29)〜[classes /:na]在java.util.HashMap.hash(HashMap.java:338)〜[na:1.8.0_91]在java.util.HashMap.put(HashMap .java:611)〜[na:1.8.0_91] at java.util.HashSet.add(HashSet.java:219)〜[na:1.8.0_91] at java.util.AbstractCollection.addAll(AbstractCollection.java:344 )〜
I have the impression that the hashcode()
method implementations for Discipline
and Student
entities use both entities. 我的印象是,
Discipline
和Student
实体的hashcode()
方法实现同时使用了这两个实体。
Maybe am I wrong, it is not very clear in the stacktrace. 也许我错了,在堆栈跟踪中不是很清楚。
How have you defined equals()
and hashcode()
methods for your entities ? 您如何为实体定义
equals()
和hashcode()
方法?
Suppose entity A
and entity B
with a bidirectional relationship. 假设实体
A
和实体B
具有双向关系。
If equals()/hashcode()
implementation of entity A
invokes equals()/hashcode()
on the entity B
field that itself invokes equals()/hashcode()
on the entity A
field, you have a cycle. 如果
equals()/hashcode()
实现实体的A
调用equals()/hashcode()
的实体B
字段本身调用equals()/hashcode()
对实体A
领域,你有一个周期。
Whereas your error. 而你的错误。
Besides, even if you cut the cycle by ensuring that only one of both refers the other in equals()/hashcode()/toString()
, you should invoke equals()/hashcode()/toString
methods of the entity relationships with cautious. 此外,即使通过确保在
equals()/hashcode()/toString()
中只有一个引用另一个来缩短周期,也应谨慎地调用实体关系的equals()/hashcode()/toString
方法。
It may have a real impact on the performance. 它可能会对性能产生实际影响。 If the Hibernate session is opened, it may indeed execute queries that you don't expect to.
如果打开了Hibernate会话,则它实际上可能会执行您不希望执行的查询。
Both of the sides have a Eager fetch type. 双方都有一个渴望获取类型。 Which means that for each Student you load, Hibernate will load every Discipline related, and for each Discipline, it will load its Students.
这意味着,对于您加载的每个学生,Hibernate将加载每个相关的学科,对于每个学科,它将加载其学生。 This is your loop.
这是你的循环。 You could change the fetch type of one side (better both), for
FetchType.LAZY
. 您可以为
FetchType.LAZY
更改一侧的获取类型(两者都更好)。 Doing that, the discipline of a student will be load just when you access the list. 这样,仅当您访问列表时,就会加载学生的纪律。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.