我有两个实体,它们之间有单向的一对多
关系。
@Entity
public class Basket {
@Id
@GeneratedValue
private Long id;
private int capacity;
}
@Entity
public class Item {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne
private Basket basket;
}
我保存了几个对象:
Basket basket1 = new Basket(100);
Basket basket2 = new Basket(200);
Basket basket3 = new Basket(300);
basketRepository.save(asList(basket1, basket2, basket3));
Item item1 = new Item("item1", basket1);
Item item11 = new Item("item11", basket1);
Item item2 = new Item("item2", basket2);
Item item22 = new Item("item22", basket2);
Item item3 = new Item("item3", basket3);
Item item33 = new Item("item33", basket3);
itemRepository.save(asList(item1, item11, item2, item22, item3, item33));
// Loading one item. Basket fetched eagerly.
itemRepository.findOne(1L);
// Loading many items. Baskets are not loaded (n+1 select problem).
itemRepository.findAll();
@ManyToOne
注解默认使用 eager fetch
。
当我使用 findOne()
加载一个 Item
时,Hibernate 会生成带有 left outer join
的查询,并在同一查询中获取 Basket
。
然而,当我使用 findAll()
时,Hibernate 先获取所有的 Items
,然后执行 N selects
(每个 Basket
一个),导致出现了所谓的 (n+1) select 问题
。为什么 Hibernate 不会在 findAll()
方法中及时获取 Basket
对象,如何修复这个问题?
@EntityGraph(attributePaths = "basket")
Spring 注释即可使方法急切地加载 'basket'。 - Cepr0@EntityGraph(value = "basket", type = EntityGraphType.FETCH)
。我在Spring仓库之外尝试了一下,所以在entityManager上手动使用setHint。更新答案。 - Madhusudana Reddy SunnapuattributePath
通过@EntityGraph
定义临时实体图,而无需显式添加@NamedEntityGraph
到您的域类型中。 - Madhusudana Reddy Sunnapu@EntityGraph
绝对是正确的选择,你不应该使用@Query
来覆盖默认的查找实现。 - Gonzalo