java - hibernate中的自引用实体会导致StackOverflowErrors

标签 java hibernate self-reference

在我的一个 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 的嵌套引用,则意味着嵌套的 Person 有另一个嵌套链接,因此它会执行子嵌套链接,依此类推。您不必使用 Person 对象引用嵌套的 Person。请使用唯一的 ID。

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

现在您有 2 个选择:使用外键或保持原样。 如果您选择第一个选项,则必须映射该nestedId,但我建议您开始使用第二个选项。这样你就有了一个 Person,它的 id 引用了一个“父亲”Person。如果nestedId是!= null OR > 0(根据您分配给id的类型),则意味着该Person是嵌套的,相反,如果id未填充或id具有默认的int值0,则意味着该Person是一个“根”,所以不是嵌套的。详细信息请参阅“层次结构数据”。

关于java - hibernate中的自引用实体会导致StackOverflowErrors,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51842552/

相关文章:

java - 按多个数字对 Java String 数组进行排序

java - 当这些表的值没有更改时,为什么 hibernate 会执行冗余更新语句?

java - hibernate 多个连接动态变化

c - 在 C 中操作链表时如何解决这个段错误问题?

C++ - 构造函数和自引用类

c# - 在自引用表中预加载 Linq to SQL 实体

java - 简单的 Quartz/Cron 作业设置

java - jmf文件播放错误

java 通过 XSD 映射到 XML

java - Hibernate 过滤器可以与条件查询一起使用吗?