java.lang.StackOverflow更新具有多对多关系的实体时出错



所以我有三个实体,EmployeeShopEmployeeShop,这是EmployeeShop的链接实体。

@Entity
@Table(name = "employee_shops")
class EmployeeShop(
@Id
@ManyToOne
var employee: Employee? = null,
@Id
@ManyToOne
var shop: Shop? = null
) : Serializable {
override fun equals(other: Any?): Boolean {
if (this === other) {
return true
}
if (other == null || javaClass != other.javaClass) {
return false
}
other as EmployeeShop
return Objects.equals(employee, other.employee) &&
Objects.equals(shop, other.shop)
}
override fun hashCode(): Int {
return Objects.hash(employee, shop)
}
}

员工

@Entity
@Table(name = "employees")
class Employee(
@Id
var id: Int? = null,
var userName: String? = null,
var email: String? = null
@OneToMany(mappedBy = "employee", cascade = [CascadeType.ALL], orphanRemoval = true)
var shops: MutableList<EmployeeShop> = mutableListOf()
) {
override fun equals(other: Any?): Boolean {
if (this === other) {
return true
}
if (other == null || javaClass != other.javaClass) {
return false
}
other as Employee
return Objects.equals(userName, other.userName) &&
Objects.equals(email, other.email)
}
override fun hashCode(): Int {
return Objects.hash(userName, email)
}
}

和商店

@Entity
@Table(name = "shops")
class Shop(
@Id
var id: Int? = null,
@OneToMany(mappedBy = "shop", cascade = [CascadeType.ALL], orphanRemoval = true)
var users: MutableList<EmployeeShop> = mutableListOf(),
) {
override fun equals(other: Any?): Boolean {
if (this === other) {
return true
}
if (other == null || javaClass != other.javaClass) {
return false
}
other as Shop
return Objects.equals(id, other.id)
}
override fun hashCode(): Int {
return Objects.hash(id)
}
}

EmployeeRepository有点像这个

interface EmployeeRepository: CrudRepository<Employee, String> {
@Query(value = "SELECT e FROM Employee e LEFT JOIN FETCH e.shops WHERE e.id = :id")
override fun findById(id: String): Optional<Employee>
}

我覆盖它的原因是添加LEFT JOIN FETCH以避免LazyInitializationException

为了从API返回,我将Employee转换为EmployeeDto

fun getDto(entity: Employee): EmployeeDto {
return EmployeeDto(
userName = entity.userName,
email = entity.email
shops = entity.shops.map { IdAndNameDto(it.shop?.id?.toString().orEmpty(), it.shop?.name.orEmpty()) }
)
}
class IdAndNameDto(val id: String = "", val name: String = "")
class EmployeeDto(
val userName: String,
val email: String,
val shops: List<IdAndNameDto>?
)

当我使用存储库更新Employee

employeeRepo.save(employee)

save来自CrudRepository(doc(。在这里,save应该返回Employee的一个实例。

我得到以下堆叠式

java.lang.StackOverflowError: null
at ch.qos.logback.classic.spi.TurboFilterList.getTurboFilterChainDecision(TurboFilterList.java:49) ~[logback-classic-1.2.3.jar:na]
at ch.qos.logback.classic.LoggerContext.getTurboFilterChainDecision_0_3OrMore(LoggerContext.java:269) ~[logback-classic-1.2.3.jar:na]
at ch.qos.logback.classic.Logger.callTurboFilters(Logger.java:751) ~[logback-classic-1.2.3.jar:na]
at ch.qos.logback.classic.Logger.isTraceEnabled(Logger.java:623) ~[logback-classic-1.2.3.jar:na]
at org.apache.logging.slf4j.SLF4JLogger.isEnabledFor(SLF4JLogger.java:213) ~[log4j-to-slf4j-2.12.1.jar:2.12.1]
at org.apache.logging.slf4j.SLF4JLogger.isEnabled(SLF4JLogger.java:121) ~[log4j-to-slf4j-2.12.1.jar:2.12.1]
at org.apache.logging.log4j.spi.AbstractLogger.isEnabled(AbstractLogger.java:1505) ~[log4j-api-2.12.1.jar:2.12.1]
at org.jboss.logging.Log4j2Logger.isEnabled(Log4j2Logger.java:46) ~[jboss-logging-3.4.1.Final.jar:3.4.1.Final]
at org.jboss.logging.Logger.isTraceEnabled(Logger.java:98) ~[jboss-logging-3.4.1.Final.jar:3.4.1.Final]
at org.jboss.logging.DelegatingBasicLogger.isTraceEnabled(DelegatingBasicLogger.java:54) ~[jboss-logging-3.4.1.Final.jar:3.4.1.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:502) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:208) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:332) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:108) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:74) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:113) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.internal.SessionImpl.fireLoadNoChecks(SessionImpl.java:1176) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1041) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:687) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.EntityType.resolve(EntityType.java:464) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.ManyToOneType.resolve(ManyToOneType.java:240) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.EntityType.resolve(EntityType.java:457) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.ComponentType.resolve(ComponentType.java:695) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:878) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:732) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.processResultSet(Loader.java:1008) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.doQuery(Loader.java:964) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:354) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:324) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.loadEntity(Loader.java:2410) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:74) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:63) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.doLoad(AbstractEntityPersister.java:4396) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4386) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:569) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:537) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:208) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:332) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:108) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:74) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:113) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.internal.SessionImpl.fireLoadNoChecks(SessionImpl.java:1176) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1041) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:687) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.EntityType.resolve(EntityType.java:464) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.ManyToOneType.resolve(ManyToOneType.java:240) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.EntityType.resolve(EntityType.java:457) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.ComponentType.resolve(ComponentType.java:695) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:878) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:732) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.processResultSet(Loader.java:1008) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.doQuery(Loader.java:964) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:354) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:324) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.loadEntity(Loader.java:2410) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:74) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:63) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.doLoad(AbstractEntityPersister.java:4396) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4386) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
...

堆栈跟踪的其余部分只是重复这几行,您也可以从上面的堆栈跟踪中看到

at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:502) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:208) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:332) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:108) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:74) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:113) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.internal.SessionImpl.fireLoadNoChecks(SessionImpl.java:1176) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1041) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:687) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.EntityType.resolve(EntityType.java:464) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.ManyToOneType.resolve(ManyToOneType.java:240) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.EntityType.resolve(EntityType.java:457) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.type.ComponentType.resolve(ComponentType.java:695) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:878) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:732) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.processResultSet(Loader.java:1008) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.doQuery(Loader.java:964) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:354) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:324) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.Loader.loadEntity(Loader.java:2410) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:74) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:63) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.doLoad(AbstractEntityPersister.java:4396) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4386) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]

但是,当我尝试用相同的save方法创建员工时,我没有任何错误。

此外,只有当employee实体包含非空的shops对象时才会发生这种情况。如果shop为空,这意味着我使用findById得到的EmployeeEmployeeShop链接表中没有任何记录,那么更新也没有任何错误。

我还是JPA的新手,所以我怀疑我声明这些实体的方式,比如我使用注释的方式,是不正确的。但我不确定问题出在哪里。

有人知道我为什么会出现StackOverflow错误吗?

我看不出你有任何明显的错误,从评论中判断,其他人也看不到。

所以你有两件事可以/应该做:

  1. 简化示例:

    • 删除代码(如equals、hashcode、properties(以获得一个最小的示例,从而了解可能引发此问题的原因
    • 尝试将其转换为Java,尽管我预计这将使问题消失,但这只是猜测
    • 使用Hibernate直接复制它,而不使用Spring Data
  2. 在堆栈跟踪中反复重复的位置设置断点。使用调试器检查值并逐步执行代码,通常这会让您至少大致了解出了什么问题,因此可能会让您了解解决方案。

  3. 如果你仍然没有发现错误,根据你在第一步中的发现,使用你在第一步骤中创建的复制器——Hibernate或Spring Data的错误。

我使用"trying-eeverhing-I-can"方法意外地解决了这个问题。

  1. 我删除了EmployeeShop实体类
  2. Employee课上,我做了这个改变。

    // old
    @OneToMany(mappedBy = "employee", cascade = [CascadeType.ALL], orphanRemoval = true)
    var shops: MutableList<EmployeeShop> = mutableListOf()
    // new
    @ManyToMany
    @JoinTable(
    name = "employee_shops",
    joinColumns = [JoinColumn(name = "employee_id")],
    inverseJoinColumns = [JoinColumn(name = "shop_id")]
    )
    var shops: MutableSet<Shop> = mutableSetOf()
    
  3. 并且在Shop类中

    // old
    @OneToMany(mappedBy = "shop", cascade = [CascadeType.ALL], orphanRemoval = true)
    var users: MutableList<EmployeeShop> = mutableListOf()
    // new
    @ManyToMany(mappedBy = "shops")
    var users: MutableSet<Employee> = mutableSetOf()
    

然后异常消失,应用程序重新开始工作。我的Hibernate/JPA知识不足以解释为什么这样做。但如果有人有同样的问题,这可能是你的解决方案。

最新更新