尝试在Spring中填充联接表时发生StackOverflow错误



我在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);

最新更新