簡體   English   中英

休眠中的自引用實體導致StackOverflowErrors

[英]self-referencing entity in hibernate causes StackOverflowErrors

在我的一個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....

除非您具有循環依賴性,否則這應該起作用。 由於存在循環依賴性,因此可能會發生StackOverflowError,這是因為無限循環遞歸地獲取了先前的狀態。

例如,當您有兩個實體A和B。A指向B,B指向A時,您將遇到無限循環,並且使用EAGER提取策略,您將得到StackOverflowError。

您需要檢查數據庫中是否沒有任何循環依賴性。

顯然這是一個錯誤。 如果您有一個實體Person,並且該實體具有對另一個Person的嵌套引用,則意味着嵌套的Person具有另一個嵌套鏈接,因此它也嵌套了子嵌套,依此類推。 您不必引用帶有Person對象的嵌套Person。 改用唯一的ID。

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

現在您有2個選擇:使用外鍵或將其保持不變。 如果選擇第一個選項,則必須映射該nestedId,但我建議您開始使用第二個選項。 這樣,您就可以擁有一個具有引用“父親”人物的ID的人物。 如果該nestedId為!= null或> 0(根據您為ID分配的類型),則表示該人是嵌套的;相反,如果未填充該ID或該ID的默認int值為0,則表示該人是“根”,因此不嵌套。 請參閱“分層數據”以獲取更多詳細信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM