我在tyring填充联接表时得到StackOverflowError。。。请参阅下面的代码。
我有两个Entite:
@Entity
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long userId;
@ManyToMany
@JoinTable(
name = "user_appointment",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "appointment_id"))
Set<Appointment> subscribedAppointments;
}
@Entity
public class Appointment {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long appointmentId;
@JsonIgnore
@ManyToMany(mappedBy = "subscribedAppointments")
Set<User> subscribers; //users who added this appointment to their calendar
}
当我尝试按以下方式填写联接表时:
user.setSubscribedAppointments(appointment); //sheikh fuad
appointment.setSubscribers(user);
appointmentRepository.save(appointment);
userRepository.save(user);
我得到堆栈溢出错误:
java.lang.StackOverflowError: null
at java.base/java.lang.Exception.<init>(Exception.java:102) ~[na:na]
at java.base/java.lang.ReflectiveOperationException.<init>(ReflectiveOperationException.java:89) ~[na:na]
at java.base/java.lang.reflect.InvocationTargetException.<init>(InvocationTargetException.java:73) ~[na:na]
at jdk.internal.reflect.GeneratedMethodAccessor60.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:56) ~[hibernate-core-5.4.15.Final.jar:5.4.15.Final]
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95) ~[hibernate-core-5.4.15.Final.jar:5.4.15.Final]
at com.taqwaapps.entity.Country$HibernateProxy$pGwXHWph.hashCode(Unknown Source) ~[classes/:na]
at com.taqwaapps.entity.City.hashCode(City.java:25) ~[classes/:na]
at jdk.internal.reflect.GeneratedMethodAccessor59.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:56) ~[hibernate-core-5.4.15.Final.jar:5.4.15.Final]
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95) ~[hibernate-core-5.4.15.Final.jar:5.4.15.Final]
at com.taqwaapps.entity.City$HibernateProxy$9IT2B41W.hashCode(Unknown Source) ~[classes/:na]
at com.taqwaapps.entity.District.hashCode(District.java:21) ~[classes/:na]
at com.taqwaapps.entity.Appointment.hashCode(Appointment.java:31) ~[classes/:na]
at java.base/java.util.ImmutableCollections$Set12.hashCode(ImmutableCollections.java:520) ~[na:na]
at com.taqwaapps.entity.User.hashCode(User.java:29) ~[classes/:na]
at com.taqwaapps.entity.Appointment.hashCode(Appointment.java:31) ~[classes/:na]
at java.base/java.util.ImmutableCollections$Set12.hashCode(ImmutableCollections.java:520) ~[na:na]
...
然后这三行重复多次:
at com.taqwaapps.entity.User.hashCode(User.java:29) ~[classes/:na]
at com.taqwaapps.entity.Appointment.hashCode(Appointment.java:31) ~[classes/:na]
at java.base/java.util.ImmutableCollections$Set12.hashCode(ImmutableCollections.java:520) ~[na:na]
为用户设置约会是否正确,反之亦然?或者如何填充spring生成的联接表?
在注释中,您使用的是Lombok的注释@EqualsAndHashCode
。
如果检查生成的代码,您将看到User正在调用约会的Set
(可能由HashSet
支持(哈希代码。Appointment也是如此,它调用用户哈希代码的Set。
龙目产生了这样的东西:
public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $set = this.getSet();
result = result * PRIME + ($set == null ? 43 : $set.hashCode());
return result;
}
如果您看到HashSet哈希代码的JDK源代码:
public int hashCode() {
int h = 0;
Iterator<E> i = iterator();
while (i.hasNext()) {
E obj = i.next();
if (obj != null)
h += obj.hashCode();
}
return h;
}
正在迭代该集合以计算每个成员的哈希代码。
既然你这么做了:
user.setSubscribedAppointments(appointment); //sheikh fuad
appointment.setSubscribers(user);
在两个setXXX中都会触发对hashcode的调用。
stackoverflow可能发生在第二行,因为用户作为约会和约会具有相同的用户。在计算哈希代码时,其中一个会反复调用另一个。
您需要在hashcode计算中打破这种依赖关系(equals方法中可能也会出现这种情况(。您需要删除或配置@EqualsAndHashCode,以便它在某个时刻中断计算。如果您自己实现散列代码,那么更简单的解决方案是仅使用主键进行计算(如果实体是持久化的(。如果实体没有持久化,那么您可以使用一些其他字段,但要注意计算中可能出现的循环性(您必须避免/破坏它(。
按以下顺序尝试。。它可能会帮助您保存记录。
appointment.setSubscribers(user);
appointmentRepository.save(appointment);
user.setSubscribedAppointments(appointment); //sheikh fuad
userRepository.save(user);
实体约会依赖于user_id,当您要保存约会时,user_id为null。所以,先保存用户,不在其中设置约会。然后为约会设置用户并保存。最后,为用户设置约会并再次保存。这意味着您必须具有以下行:
userRepository.save(user);
appointment.setSubscribers(user);
appointmentRepository.save(appointment);
user.setSubscribedAppointments(appointment);
userRepository.save(user);