为什么Spring JPA存储库总是以@GetMapping方法急切加载?

时间:2019-05-17 13:01:46

标签: spring hibernate jpa

我想通过使用spring jpa和hibernate创建一个简单的多对多关系,这是代码:

@Entity
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column(name = "name")
    private String name;

    @ManyToMany(cascade = CascadeType.ALL,
    fetch = FetchType.LAZY)
    @JoinTable(name = "book_publisher",
        joinColumns = @JoinColumn(name = "book_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "publisher_id", referencedColumnName = "id"))
    private Set<Publisher> publishers;

@Entity
public class Publisher {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    private String name;

    @ManyToMany(mappedBy = "publishers"
    , fetch = FetchType.LAZY)
    @Nullable
    private Set<Book> books = new HashSet<>();

    public Publisher(String name) {
        this.name = name;
    }

所有集合都是按照上面的代码懒洋洋地获取的。

然后我创建了两个实体的两个存储库:

public interface PublisherRepository extends JpaRepository<Publisher, Integer>{
}
public interface BookRepository extends JpaRepository<Book, Integer>{

}

然后我创建一个简单的控制器:

    @GetMapping("/getPublisher/{id}")
    public Publisher getPublisher(@PathVariable Integer id) {
        return publisherRepository.findById(id).get();
    }

一些奇怪的事情发生了:

当我通过curl拨打http时,收到了这样的回复:

{“ id”:1,“ name”:“ YanYan”,“ books”:[{“ id”:1,“ name”:“ Avengers”,“ publishers”:[{“ id”:1, “ name”:“ YanYan”,“ books”:[{“ id”:1,“ name”:“ Avengers”,“ publishers”:[{“ id”:1,“ name”:“ YanYan”,“ books “:[{” id“:1,”名称“:”复仇者“,”出版商“:[{” id“:1,”名称“:” YanYan“,”书籍“:[{” id“:1, “ name”:“ Avengers”,“ publishers”:[{“ id”:1,“ name”:“ YanYan”,“ books”:[{“ id”:1,“ name”:“ Avengers”,“ publishers “:[{” id“ .....

表示它们都不是延迟获取的,这将导致无限循环。

谁能告诉我为什么?

1 个答案:

答案 0 :(得分:2)

我可以看到2个问题:

  1. 延迟加载:

检查是否明确配置了spring.jpa.open-in-view。 不幸的是,默认值为true

您可以通过以下网址获取有关此设置的更多信息:What is this spring.jpa.open-in-view=true property in Spring Boot?

如果未配置,you may receive a warning on startup

WebConfiguration$JpaWebMvcConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
  1. JSON序列化

您有2个相互交叉引用的实体,当您序列化出版商时,您还序列化了图书,但该图书具有您已经访问过的出版商。在序列化阶段,您将进入一个无限循环。

要么使用JSON注释从序列化中排除关系的一侧,要么使用自定义DTO传输数据。

更新

我希望当您设置spring.jpa.open-in-view = false并且不指定要获取的内容时,您将开始有LazyInitializationException。这是因为您在将字段序列化为JSON时仍尝试访问这些字段(但是现在对象未附加到会话)。与您的评论相反,这是一个证明集合延迟加载的证明(这意味着,您有一个代理而不是一个集合。您可以访问此代理,这会强制加载,但前提是会话仍处于打开状态(同一事务或打开) -in-in-view设置)。

我的建议:首先攻击JSON序列化,这是真正的错误。修复之后,担心获取策略。