java Spring Boot JPA - OneToMany 关系导致无限循环

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33234546/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 21:24:14  来源:igfitidea点击:

Spring Boot JPA - OneToMany relationship causes infinite loop

javahibernatejpaspring-boot

提问by Smajl

I have a two objects with simple @OneToMany relationship which looks as follows:

我有两个具有简单 @OneToMany 关系的对象,如下所示:

parent:

家长:

@Entity
public class ParentAccount {

  @Id
  @GeneratedValue
  private long id;
  private String name;

  @OneToMany(fetch = FetchType.EAGER, mappedBy = "parentAccount")
  private Set<LinkedAccount> linkedAccounts;

}

child:

孩子:

@Entity
public class LinkedAccount {

  @Id
  @GeneratedValue
  private long id;

  @ManyToOne(optional = false)
  private ParentAccount parentAccount;

  private String name;

  // empty constructor for JPA
  public LinkedAccount() {
  }

}

I ma using Spring CrudRepositoryto operate with these entities. However, when calling ParentAccount parent = parentAccountRepository.findOne(id);, some kind of infinite loop starts happening and hibernate spams this all over the console:

我使用 SpringCrudRepository来操作这些实体。但是,当调用 时ParentAccount parent = parentAccountRepository.findOne(id);,某种无限循环开始发生并且休眠垃圾邮件会在整个控制台中发送:

Hibernate: select linkedacco0_.parent_account_id as parent_a6_1_0_, linkedacco0_.id as id1_0_0_, linkedacco0_.id as id1_0_1_, linkedacco0_.aws_id as aws_id2_0_1_, linkedacco0_.key_id as key_id3_0_1_, linkedacco0_.name as name4_0_1_, linkedacco0_.parent_account_id as parent_a6_0_1_, linkedacco0_.secret_key as secret_k5_0_1_ from linked_account linkedacco0_ where linkedacco0_.parent_account_id=?

I tried changed the fetch type to LAZY but then I get this error:

我尝试将获取类型更改为 LAZY,但随后出现此错误:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.berrycloud.scheduler.model.ParentAccount.linkedAccounts, could not initialize proxy - no Session

(It seems that it is trying to do the lazy load outside of the transactional context).

(似乎它正在尝试在事务上下文之外执行延迟加载)。

This is my CRUD repository:

这是我的 CRUD 存储库:

@Repository
public interface ParentAccountRepository extends CrudRepository<ParentAccount, Long> {
}

Could someone tell me how to resolve this issue? I would prefer the solution with EAGER fetch. Thank you for any tips

有人能告诉我如何解决这个问题吗?我更喜欢 EAGER fetch 的解决方案。谢谢你的任何提示

EDIT: here is the schema I am using

编辑:这是我正在使用的架构

CREATE TABLE parent_account (
    id BIGINT auto_increment,
    name VARCHAR(80) null,
    PRIMARY KEY (`id`)
);

CREATE TABLE linked_account (
    id BIGINT auto_increment,
    parent_account_id BIGINT,
    name VARCHAR(80) null,
    FOREIGN KEY (`parent_account_id`) REFERENCES `parent_account` (`id`),
    PRIMARY KEY (`id`)
);

采纳答案by Smajl

Problem solved. I was using a custom @toStringmethod in the LinkedAccount which was referencing the ParentAccount. I had no idea that this could cause any problem and therefor I did not include the toString in my question.

问题解决了。我@toString在 LinkedAccount 中使用了一个引用 ParentAccount的自定义方法。我不知道这会导致任何问题,因此我没有在我的问题中包含 toString。

Apparently, this was causing an infinite loop of lazy loading and removing this reference fixed the problem.

显然,这导致了延迟加载的无限循环,删除此引用解决了问题。

回答by user1819111

As the first answer suggests:

正如第一个答案所暗示的那样:

Do not use Lombok's @Dataannotation on @Entityclasses.

不要@Data@Entity类上使用 Lombok 的注释。

Reason:@Datagenerates hashcode(), equals()and toString()methods that use the generated getters. Using the getter means of course fetching new data even if the property was marked with FetchType=LAZY.

原因:@Data生成hashcode()equals()以及toString()使用生成的 getter 的方法。即使属性被标记为FetchType=LAZY ,使用 getter 当然也意味着获取新数据。

Somewhere along the way hibernate tries to log the data with toString()and it crashes.

在 Hibernate 尝试记录数据的过程中的某个地方toString(),它崩溃了。

回答by Mejmo

Something like this does not work?

像这样的东西不起作用?

@Entity
public class Account {

    @Id
    @GeneratedValue
    private long id;
    private String name;

    @ManyToOne(cascade={CascadeType.ALL})
    @JoinColumn(name="manager_id")
    private Account manager;

    @OneToMany((fetch = FetchType.EAGER, mappedBy="manager")
    private Set<Account> linkedAccounts = new HashSet<Account>();

}

回答by Mejmo

I recently had this issue due to a poorly defined Hymanson2HttpMessageConverter.

由于 Hymanson2HttpMessageConverter 定义不明确,我最近遇到了这个问题。

I had done something like the following.

我做了类似以下的事情。

@Bean
RestTemplate restTemplate(@Qualifier("halHymansonHttpMessageConverter")
                                  TypeConstrainedMappingHymanson2HttpMessageConverter halConverter) {
    final RestTemplate template = new RestTemplateBuilder().build();
    halConverter.setSupportedMediaTypes(List.of(/* some media types */)); 
    final List<HttpMessageConverter<?>> converters = template.getMessageConverters();
    converters.add(halConverter);
    template.setMessageConverters(converters);
    return template;
}

This caused a problem because the media types did not include all the defaults. Changing it to the following fixed the issue for me.

这导致了一个问题,因为媒体类型不包括所有默认值。将其更改为以下内容为我解决了问题。

halConverter.setSupportedMediaTypes(
    new ImmutableList.Builder<MediaType>()
        .addAll(halConverter.getSupportedMediaTypes())
        .add(/* my custom media type */)
        .build()
);