尝试在 Spring 中填充联接 table 时出现 StackOverflowError?
StackOverflowError when trying to fill join table in Spring?
我在尝试填充连接时收到 WhosebugError table...请参阅下面的代码。
我有两个实体:
@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
}
当我尝试按如下方式填充联接 table 时:
user.setSubscribedAppointments(appointment); //sheikh fuad
appointment.setSubscribers(user);
appointmentRepository.save(appointment);
userRepository.save(user);
我收到 WhosebugError:
java.lang.WhosebugError: 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$HibernateProxyIT2B41W.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?
生成的连接 table
按此顺序尝试..它可能会帮助您保存记录。
appointment.setSubscribers(user);
appointmentRepository.save(appointment);
user.setSubscribedAppointments(appointment); //sheikh fuad
userRepository.save(user);
根据评论,您正在使用 Lombok 的注释 @EqualsAndHashCode
。
如果您检查生成的代码,您会看到 User 正在调用 Set
of Appointments(可能由 HashSet
支持)哈希码。 Appointment 调用用户哈希码的 Set 也是如此。
Lombok 生成如下内容:
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 的调用。
Whosebug 可能出现在第二行,因为 user as appointment 和 appointment 具有相同的用户。在计算hashcode的时候,一个一遍又一遍的调用另一个。
你需要在哈希码计算中打破这种依赖关系(可能同样发生在 equals 方法中)。您需要删除或配置 @EqualsAndHashCode,因此它确实会在某些时候中断计算。如果您自己实现哈希码,那么更简单的解决方案是仅使用主键(如果实体是持久化的)进行计算。如果实体没有持久化,那么你可以使用一些其他字段,但要注意计算中可能发生的循环(你必须avoid/break它)。
实体约会依赖于 user_id,当您要保存约会时它为空。所以首先保存用户而不在其中设置约会。然后设置用户预约并保存。最后,为用户设置约会并再次保存。这意味着您必须具有以下几行:
userRepository.save(user);
appointment.setSubscribers(user);
appointmentRepository.save(appointment);
user.setSubscribedAppointments(appointment);
userRepository.save(user);
我在尝试填充连接时收到 WhosebugError table...请参阅下面的代码。
我有两个实体:
@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
}
当我尝试按如下方式填充联接 table 时:
user.setSubscribedAppointments(appointment); //sheikh fuad
appointment.setSubscribers(user);
appointmentRepository.save(appointment);
userRepository.save(user);
我收到 WhosebugError:
java.lang.WhosebugError: 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$HibernateProxyIT2B41W.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?
生成的连接 table按此顺序尝试..它可能会帮助您保存记录。
appointment.setSubscribers(user);
appointmentRepository.save(appointment);
user.setSubscribedAppointments(appointment); //sheikh fuad
userRepository.save(user);
根据评论,您正在使用 Lombok 的注释 @EqualsAndHashCode
。
如果您检查生成的代码,您会看到 User 正在调用 Set
of Appointments(可能由 HashSet
支持)哈希码。 Appointment 调用用户哈希码的 Set 也是如此。
Lombok 生成如下内容:
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 的调用。
Whosebug 可能出现在第二行,因为 user as appointment 和 appointment 具有相同的用户。在计算hashcode的时候,一个一遍又一遍的调用另一个。
你需要在哈希码计算中打破这种依赖关系(可能同样发生在 equals 方法中)。您需要删除或配置 @EqualsAndHashCode,因此它确实会在某些时候中断计算。如果您自己实现哈希码,那么更简单的解决方案是仅使用主键(如果实体是持久化的)进行计算。如果实体没有持久化,那么你可以使用一些其他字段,但要注意计算中可能发生的循环(你必须avoid/break它)。
实体约会依赖于 user_id,当您要保存约会时它为空。所以首先保存用户而不在其中设置约会。然后设置用户预约并保存。最后,为用户设置约会并再次保存。这意味着您必须具有以下几行:
userRepository.save(user);
appointment.setSubscribers(user);
appointmentRepository.save(appointment);
user.setSubscribedAppointments(appointment);
userRepository.save(user);