【发布时间】:2020-06-29 14:00:48
【问题描述】:
我有下表架构,其中 simulation 有很多 searches 并且任何 search 都有很多 properties .
由于我想一次性保存一个 Simulation 实体及其搜索及其属性,因此我将我的实体映射如下:
Simulation.java
@Data
@EqualsAndHashCode(of = "id")
@ToString(exclude = "searches")
@Entity
@Table(name = "SIMULATION")
public class Simulation implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "simulation_generator")
@SequenceGenerator(name = "simulation_generator", sequenceName = "SIMULATION_SEQ", allocationSize = 1)
private Long id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "SIMULATION_ID")
private Set<SimulationSearch> searches = new HashSet<>(0);
// other fields
}
SimulationSearch.java
@Data
@EqualsAndHashCode(of = "id")
@ToString(exclude = "properties")
@Entity
@Table(name = "SIM_SEARCH")
public class SimulationSearch implements Serializable {
@EmbeddedId
private SimulationSearchId id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumns({
@JoinColumn(name = "SIMULATION_ID", referencedColumnName = "SIMULATION_ID"),
@JoinColumn(name = "POSITION", referencedColumnName = "POSITION")
})
private Set<SimulationSearchProperty> properties = new HashSet<>(0);
// other fields...
@Data
public static class SimulationSearchId implements Serializable {
@ManyToOne
@JoinColumn(name = "SIMULATION_ID", insertable = false, updatable = false)
private Simulation simulation;
private int position;
}
}
SimulationSearchProperties.java
@Data
@EqualsAndHashCode(of = "id")
@Entity
@Table(name = "SIM_SEARCH_PROPERTY")
public class SimulationSearchProperty implements Serializable {
@EmbeddedId
private SimulationSearchPropertyId id;
private String value;
@Data
public static class SimulationSearchPropertyId implements Serializable {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({
@JoinColumn(name = "SIMULATION_ID", referencedColumnName = "SIMULATION_ID", insertable = false, updatable = false),
@JoinColumn(name = "POSITION", referencedColumnName = "POSITION", insertable = false, updatable = false)
})
private SimulationSearch search;
private String label;
}
}
Hibernate 会一直打印以下查询,直到出现 StackOverflowError。
select simulation0_.*, searches1_.*, properties5_.*
from simulation simulation0_
left outer join sim_search searches1_ on simulation0_.id = searches1_.simulation_id
left outer join sim_search_property properties5_ on searches1_.position = properties5_.position and searches1_.simulation_id = properties5_.simulation_id
where simulation0_.id = ?
虽然Simulation 和SimulationSearch 之间的映射与SimulationSearch 和SimulationSearchProperty 映射非常相似,但是当我将ManyToOne 的ManyToOne 注释设置为延迟获取并且甚至没有停止时,这个错误就开始发生了如果我也将SimulationSearchPropertyId#search 设置为懒惰。
我错过了什么?
更新
我使用的是 Hibernate 4.2.6.Final
部分堆栈跟踪日志:
java.lang.StackOverflowError
at org.hibernate.engine.spi.QueryParameters.<init>(QueryParameters.java:148)
at org.hibernate.engine.spi.QueryParameters.<init>(QueryParameters.java:104)
at org.hibernate.engine.spi.QueryParameters.<init>(QueryParameters.java:81)
at org.hibernate.loader.Loader.loadEntity(Loader.java:2114)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:82)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:72)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3927)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:460)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:429)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:206)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:262)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:150)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1092)
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1019)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:672)
at org.hibernate.type.EntityType.resolve(EntityType.java:490)
at org.hibernate.type.ComponentType.resolve(ComponentType.java:667)
at org.hibernate.type.ComponentType.nullSafeGet(ComponentType.java:349)
at org.hibernate.type.ManyToOneType.hydrate(ManyToOneType.java:190)
at org.hibernate.type.ComponentType.hydrate(ComponentType.java:642)
at org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:775)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:708)
at org.hibernate.loader.Loader.processResultSet(Loader.java:943)
at org.hibernate.loader.Loader.doQuery(Loader.java:911)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:342)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:312)
at org.hibernate.loader.Loader.loadEntity(Loader.java:2121)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:82)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:72)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3927)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:460)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:429)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:206)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:262)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:150)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1092)
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1019)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:672)
at org.hibernate.type.EntityType.resolve(EntityType.java:490)
at org.hibernate.type.ComponentType.resolve(ComponentType.java:667)
at org.hibernate.type.ComponentType.nullSafeGet(ComponentType.java:349)
at org.hibernate.type.ManyToOneType.hydrate(ManyToOneType.java:190)
at org.hibernate.type.ComponentType.hydrate(ComponentType.java:642)
at org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:775)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:708)
at org.hibernate.loader.Loader.processResultSet(Loader.java:943)
at org.hibernate.loader.Loader.doQuery(Loader.java:911)
...
我刚刚更新了一点实体映射,删除了mappedBy 注释属性并添加了@JoinColumns 注释。
现在持久性工作正常,但是当我尝试加载单个模拟时 StackOverflowError 仍然存在。
我还清理了 Hibernate 生成的 sql,删除了无趣的信息。
【问题讨论】:
-
请同时包含stackoverflow异常的stacktrace。
-
你用的是什么休眠版本?
-
我已经更新了我的问题,顺便说一句,异常只是内部调用,我使用的是 Hibernate 4.2.6
-
看起来您的注释不正确... Hibernate 无法识别您具有双向关系并将您的关系视为单向关系。我稍后会尝试形成一个正确的答案......
-
这似乎不是导致 stackoverflow 错误的哈希或 toString 递归:我尝试删除
@Data以支持@Getter和@Setter在SimulationSearchPropertyId但没有任何改变.
标签: java hibernate stack-overflow hibernate-mapping