我想通过使用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“ .....
表示它们都不是延迟获取的,这将导致无限循环。
谁能告诉我为什么?
答案 0 :(得分:2)
我可以看到2个问题:
检查是否明确配置了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
您有2个相互交叉引用的实体,当您序列化出版商时,您还序列化了图书,但该图书具有您已经访问过的出版商。在序列化阶段,您将进入一个无限循环。
要么使用JSON注释从序列化中排除关系的一侧,要么使用自定义DTO传输数据。
更新
我希望当您设置spring.jpa.open-in-view = false
并且不指定要获取的内容时,您将开始有LazyInitializationException。这是因为您在将字段序列化为JSON时仍尝试访问这些字段(但是现在对象未附加到会话)。与您的评论相反,这是一个证明集合延迟加载的证明(这意味着,您有一个代理而不是一个集合。您可以访问此代理,这会强制加载,但前提是会话仍处于打开状态(同一事务或打开) -in-in-view设置)。
我的建议:首先攻击JSON序列化,这是真正的错误。修复之后,担心获取策略。