休眠中的自引用实体会导致堆栈溢出错误



在我的一个Java实体(MyState(中,我有一个对它的引用。批注如下所示:

@OneToOne
@JoinColumn(name = "previousStateId", nullable = true,
foreignKey = @ForeignKey(name = "fk_state_previousstate"))
private MyState previousState;

这曾经工作得很好,直到表格增长,越来越多的州相互指向。现在,当我尝试获取最新的MyState时,由于嵌套太深而发生StackOverflowError。还有什么网站比这里更适合问我的问题呢?;-)

我最终需要访问根状态(长链状态中的第一个(,还需要访问以前的状态。

有没有办法避免获得所有参考?我试图添加一个指向原始状态的新字段"rootState"。这当然是 2 个状态的短链,所以效果很好。

但是,我确实也需要以前的状态。我应该尝试通过将 previousState 的 previousState 设置为 null 来手动断开链条,还是有更好的选择?

---编辑

我检查以确保在相互指向的状态下没有循环,没有。

堆栈跟踪的一部分:

Caused by: java.lang.StackOverflowError
at com.mchange.v2.c3p0.impl.NewPooledConnection.handleThrowable(NewPooledConnection.java:492)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.getWarnings(NewProxyPreparedStatement.java:1045)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.handleAndClearWarnings(SqlExceptionHelper.java:317)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logAndClearWarnings(SqlExceptionHelper.java:273)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(JdbcCoordinatorImpl.java:529)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.release(JdbcCoordinatorImpl.java:421)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:160)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:102)
at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:186)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4126)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:502)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:467)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:212)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:258)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:150)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1070)
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:989)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:716)
at org.hibernate.type.EntityType.resolve(EntityType.java:502)
at org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:170)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:144)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.performTwoPhaseLoad(AbstractRowReader.java:244)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:215)
at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:140)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:138)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:102)
at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:186)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4126)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:502)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:467)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:212)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:258)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:150)
.... and on and on and on....

显然这是一个错误。 如果您有一个实体 Person,并且该实体具有对另一个 Person 的嵌套引用,则意味着嵌套的人员具有另一个嵌套链接,因此它会执行子嵌套链接,依此类推。不必使用"人员"对象引用嵌套的"人员"。请改用唯一 ID。

public class Person{
private int idNestedPerson;
//fields + getters/setters
}

现在您有 2 个选择:使用外键或保持原样。 如果您选择第一个选项,则必须映射该nestedId,但我建议您开始使用第二个选项。这样,您就拥有一个 ID 引用"父亲"的人。如果该嵌套ID是!=空或>0(根据您分配给id的类型(,则表示Person是嵌套的,相反,如果未填充id或id具有默认的int值为0,则表示Person是"根",因此未嵌套。有关更多详细信息,请参阅"分层数据"。

这应该有效,直到您具有循环依赖关系。对于循环依赖关系,StackOverflowError 可能会发生,因为无限循环递归地获取以前的状态。

例如,当您有两个实体 A 和 B 时。A 指向 B,B 指向 A,那么你就有了无限循环,使用 EAGER 获取策略,你最终会得到 StackOverflowError。

您需要检查数据库中是否没有任何循环依赖项。

最新更新