Hibernate OneToMany java.lang.StackOverflowError

79

这是我在stack上的第一个问题,请大家温柔点:D

我正在尝试创建hibernate的OneToMany关系。当我尝试从数据库中获取一些数据时,出现了StackOverflowError错误。但是当我删除OneToMany部分时,一切都正常。这是我的REST服务的一部分,目前它运行在VMware vFabric服务器和MySQL数据库上。

获取示例:

@Inject
private EntityManager entityManager;
...
entityManager.find(League.class, 1);
...
entityManager.find(Team.class, 1);

MySQL脚本:

CREATE TABLE league (
    id int(11) NOT NULL AUTO_INCREMENT,
    name varchar(20) COLLATE utf8_unicode_ci NOT NULL,
    PRIMARY KEY (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE team (
    team_id int(11) NOT NULL AUTO_INCREMENT,
    name varchar(20) COLLATE utf8_unicode_ci NOT NULL,
    fk_leagueId int(11) NOT NULL,
    PRIMARY KEY (team_id),
    FOREIGN KEY (fk_leagueId) REFERENCES league(id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

类:

@XmlRootElement
@Entity
@Table(name = "team")
@Data
public class Team {
    @Id
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    @Column(name = "team_id")
    private int id;
    @Column(name = "name")
    private String name;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "fk_leagueId", nullable = false)
    private League league;
}

@XmlRootElement
@Entity
@Table(name = "league")
@Data
public class League {
    @Id
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    @Column(name = "id")
    private int id;
    @Column(name = "name")
    private String name;
    //if I comment 2 lines below, there is no error, and everything works fine
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "league")
    private Set<Team> teams;
}

错误:

Hibernate: select league0_.id as id1_1_0_, league0_.name as name2_1_0_ from league league0_ where league0_.id=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Hibernate: select teams0_.fk_leagueId as fk3_1_1_, teams0_.team_id as team1_4_1_, teams0_.team_id as team1_4_0_, teams0_.fk_leagueId as fk3_4_0_, teams0_.name as name2_4_0_ from team teams0_ where teams0_.fk_leagueId=?
Exception in thread "tomcat-http--3" java.lang.StackOverflowError
    at org.jboss.logging.JDKLogger.translate(JDKLogger.java:73)
    at org.jboss.logging.JDKLogger.isEnabled(JDKLogger.java:85)
    at org.jboss.logging.JDKLogger.doLog(JDKLogger.java:41)
    at org.jboss.logging.Logger.debug(Logger.java:406)
    at org.hibernate.internal.CoreMessageLogger_$logger.debug(CoreMessageLogger_$logger.java:525)
    at org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:104)
    at org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:95)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:180)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:159)
    at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1858)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1835)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1815)
    at org.hibernate.loader.Loader.doQuery(Loader.java:899)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:341)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:311)
    at org.hibernate.loader.Loader.loadCollection(Loader.java:2234)
    at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:65)
    at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:674)
    at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:83)
    at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1849)
    at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:549)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:234)
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:545)
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:124)
    at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:428)
    at com.lukaszb.motspe.webapp.model.League.hashCode(League.java:21)
    at com.lukaszb.motspe.webapp.model.Team.hashCode(Team.java:20)
    at java.util.HashMap.hash(HashMap.java:351)
    at java.util.HashMap.put(HashMap.java:471)
    at java.util.HashSet.add(HashSet.java:217)
...

编辑:

感谢@Thihara和@KarIP的帮助,我已经成功解决了这个问题。我像这样重写了Team和League的toString()方法:

@Override
public String toString() {
    return "League [id=" + id + ", name=" + name + "]";
}

@Override
public String toString() {
    return "Team [id=" + id + ", name=" + name + "]";
}

我能够按照预期从数据库中获取数据。但是在解析时,我遇到了有无限循环的JAXB错误。因此,我使用@XmlAccessorType(XmlAccessType.FIELD)对Team和League类进行了注释,以便它不会查看方法,并且将Team league字段标记为@XmlTransient,以便它不会被解析。

在这里,我甚至可以删除我的toString()实现,它仍然有效。我不完全确定原因。问题已经解决,但我想听听更精确的解释。我不知道为什么JAXB会停止数据提取,即使它是在整个数据库通信过程之后(或者不是?)。更具体地说,我正在使用Jersey:

@GET
@Path("search/id")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public List<League> searchById(@QueryParam("id") int id) {
return Arrays.asList(leagueDAO.getById(id));
}

在你的联赛类中,你已经定义了一组团队,但是在它的getter和setter上方放置了一个one to many注释。 - shreyansh jogi
这是一个好问题,所以我给你点赞。 - Siddharth
类似的问题和解决方案:https://dev59.com/T3PYa4cB1Zd3GeqPjoAp - dkb
15个回答

142
我曾遇到过类似的问题。我在我的模型对象上使用了Lombok的@Data注解来自动生成getter、setter和其他标准方法。我认为由Lombok生成的toString()方法在我的TeamLeague对象之间引入了循环依赖。当我尝试从我的League对象获取Set<teams> teams时,我得到了一个java.lang.StackOverflowError,因为Spring调用了toString()方法以记录日志。
我通过取消Lombok的toString()方法来解决这个问题。我用Lombok的@Getter@Setter注解替换了@Data注解。这样我仍然可以从免费的getter和setter中受益,而不必使用toString()方法。

33
谢谢,这很有帮助。或者您仍然可以使用@Data注释,但需添加@ToString注释并指定一个排除的属性,例如:@ToString(exclude = {"propName"}) - Wet Noodles
1
我们可以保留@ToString注释,只是排除导致递归的字段。这可以通过在每个这样的字段之前放置Lombok ToString.Exclude注释来实现。请参阅:https://projectlombok.org/features/ToString - Alok P
我想补充一下,在我的情况下,当调用hascode时,我可以看到循环依赖发生。我保留了@Data并添加了@EqualsAndHashCode(of = {"id"})。 - Denis Klein

38

如果你的团队联赛被递归访问,那么它唯一可能引发StackOverFlow异常......

团队到联赛到团队到联赛

我猜测有些函数试图通过反射或递归地将你的对象转换为其他表示形式,结果导致了无限循环。


1
谢谢,这给了我一个解决方案。 - otocon
11
谢谢建议!对我来说,在一个多对多的id类中是 hashCode. - SaganTheBest
6
在面对类似问题时,我偶然发现了这篇文章。我的情况和问题描述中提到的关系非常相似,该问题不仅出现在toString()方法中,而且(在我的情况下)也出现在LomBok提供的默认实现的哈希码中。我的即时解决方案是从toString()和hashcode()方法中排除有问题的字段,还考虑将OneToMany关系的所有权转移给"One"一侧,这可能有助于克服问题,但这个解决方案可能会让你措手不及,因为应用程序周围没有适当的端到端测试! - HackerMonkey
4
在我的情况下,toString() 方法存在递归调用。 - Vivek Panday
2
哦,天啊。我一直在尝试解决这个问题,从早上开始就没停过。没想到是Lombok搞的鬼。感谢你挽救了我的一天。 - Pavan Jadda
显示剩余2条评论

36

如果您使用@Data注解,Lombok自动生成的toString()方法可能会导致循环依赖。要排除某个字段的循环依赖:

@Entity
@Data
public class Team {

  ...

  @ToString.Exclude
  @ManyToOne
  private League league;
}

4
使用@ToString.Exclude(以及@EqualsAndHashCode.Exclude)获得+1——比起使用@...(exclude = {"children"})更加简洁明了。 - Josh M.

24
我遇到了这个错误,因为我正在使用Jackson将映射在双向OneToMany和ManyToOne上的对象列表解析为JSON,从而导致无限循环。

如果你也遇到这种情况,可以使用@JsonManagedReference和@JsonBackReference注解来解决。

来自API的定义:

示例:

Owner.java:

@JsonManagedReference
@OneToMany(mappedBy = "owner", fetch = FetchType.EAGER)
Set<Car> cars;

Car.java:

@JsonBackReference
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "owner_id")
private Owner owner;

另一个解决方案是使用@JsonIgnore,这将只是将字段设置为null


如果我在获取时仍然想要在Car对象中拥有Owner,我该怎么办?我需要在Owner中拥有Car,但同时也需要在Car中拥有Owner,这是否可能而不进行DTO和繁琐的映射呢? - Spialdor
1
@Jessy,你可以使用@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")来替代循环引用,只保留一个ID。 - DanielJ
这个方法非常有效,可以解决在实体转换为DTO时出现的循环依赖问题。 - Yash Joshi

10

对于我来说,Lombok提供的hashCode和toString默认实现都导致了这个问题。

您可以使用此注释来排除成员以在单个注释中同时使用equalsAndHasCode:

@EqualsAndHashCode(exclude = {"certificates", "payment"})

如果您想要在equals方法中排除成员变量,Lombok提供了@ToString.Exclude注解。

@ToString.Exclude
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "shipment")
    private Set<Certificate> certificates;

1
非常感谢,这解决了我的问题。此外,我们可以在属性上使用@EqualsAndHashCode.Exclude - Suge
请给这位先生一块饼干。谢谢您,先生。但是垃圾回收怎么样了?我们有删除对象的问题吗? - Ivan Demin

9

我用Lombok的@Getter和@Setter注解替换了@Data注解。


2
你应该提供一个完整的代码示例,说明旧代码为什么无法工作以及你的解决方案如何修复它。 - user254694
谢谢,这个更改解决了我的问题!Data注释会生成(除其他外)考虑所有属性的toString方法,这意味着如果你在双向关系的两侧都有它(比如OneToMany和ManyToOne),toString方法将递归地从一个实体到另一个实体,最终导致StackOverflow错误。使用Getter和Setter替换它可以避免生成这个toString方法,在大多数情况下可能并不必要。 - Cécile Fecherolle

4

我曾经有过类似的问题,在我的情况下,这些方法都没有起到作用。

这个方法帮了我:

@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "order_id")
@Fetch(value = FetchMode.SUBSELECT)
private List<Product> orderLines; 

“order_id”是Product表的外键列。

而我没有在Product实体中添加任何内容。


3

我曾经遇到一个问题,由于 Kotlin 抛出了 Stackoverflow 异常,我苦苦思索很长时间,认为这是 Kotlin 的问题。最终发现是 Jackson 引起的,Jackson 被 Spring Hibernate 使用并导致了 Stackoverflow。

你可以通过在两端设置 @JsonIgnoreProperties 来解决这个问题。例如:

public class ProductEntity implements Serializable {

private List<ProductPriceEntity> refProductPriceEntities = new ArrayList<>();

@OneToMany(
        mappedBy = "product",
        fetch = FetchType.LAZY,
        cascade = CascadeType.ALL,
        orphanRemoval = true,
        targetEntity = ProductPriceEntity.class)
  @JsonIgnoreProperties(value = "product", allowSetters = true)
  public List<ProductPriceEntity> getRefProductPriceEntities() {
    return refProductPriceEntities;
  }

  public void setRefProductPriceEntities(List<ProductPriceEntity> refProductPriceEntities) {
    this.refProductPriceEntities = refProductPriceEntities;
  }
}

最后,造成了stackoverflow异常的另一面。

public class ProductPriceEntity {

private ProductEntity product;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({
        @JoinColumn(name = "product_id", referencedColumnName = "id", nullable = false),
        @JoinColumn(name = "product_version_id", referencedColumnName = "version_id", nullable = false)
})
@JsonIgnoreProperties(value = "refProductPriceEntities", allowSetters = true)
public ProductEntity getProduct() {
    return product;
}

public void setProduct(ProductEntity product) {
    this.product = product;
}
}

2
在Hibernate中的OneToOne映射中,出现了这个错误:实体类无法将toString转换。
Class A(Details.class)-
@OneToOne
@JoinColumn(name="billing_address_id")
private Address billingAddress;

@OneToOne
@JoinColumn(name="shipping_address_id")
private Address shippingAddress;


Class B(Address.class)-
@OneToOne(mappedBy="billingAddress")
private Details billingDetails;

@OneToOne(mappedBy="shippingAddress")
private Details shippingDetails;

错误- 因为A类调用B类,同样地,B类也调用了A类。 需要删除其中一个类。 然后此问题将得到解决。


1
当我遇到这个问题时,我可以通过使用@JsonManagedReference@JsonBackReference来解决它,但这意味着在将其反序列化为json时,实体的只有一侧具有子元素。即,在您的团队和联赛示例中,只有联赛会显示球队,而球队不会显示它属于哪个联赛。
为了允许双方,需要在实体中使用@JsonIdentityInfo注释并删除@JsonBackReference@JsonManagedReference。您的实体将如下所示:
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Team {
...

这个替换了我所寻找的循环引用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接