web-dev-qa-db-ja.com

SpringデータのfindAll()は熱心にフェッチしません

単方向の_one to many_関係を持つ2つのエンティティがあります。

_@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()を使用して1つのItemをロードすると、Hibernateは_left outer join_でクエリを生成し、Basketは同じクエリでフェッチされます。ただし、findAll()を使用すると、Hibernateは最初にすべてのItemsをフェッチし、次に_N selects_(Basketごとに1つ)を実行するため、_(n+1) select problem_。 HiberanteがfindAll()メソッドでBasketオブジェクトを熱心にフェッチしないのはなぜですか?これを修正する方法は?

5
k13i

リポジトリ内の@Queryアノテーションを使用してfindAllメソッドをオーバーライドできます。以下はサンプルコードです

public interface ItemRepository extends CrudRepository<Item, Long> {
    @Override
    @Query("select item from Item item left join fetch item.basket")
    Iterable<Item> findAll();
}

次に、SQLクエリをログに記録して、クエリが1つだけ行われていることを確認できます。

Hibernate: select item0_.id as id1_1_0_, basket1_.id as id1_0_1_, item0_.basket_id as basket_i3_1_0_, item0_.name as name2_1_0_, basket1_.capacity as capacity2_0_1_ from item item0_ left outer join basket basket1_ on item0_.basket_id=basket1_.id

そしてそれがあった前に

2018-03-09 13:26:52.269  INFO 4268 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select item0_.id as id1_1_, item0_.basket_id as basket_i3_1_, item0_.name as name2_1_ from item item0_
Hibernate: select basket0_.id as id1_0_0_, basket0_.capacity as capacity2_0_0_ from basket basket0_ where basket0_.id=?
Hibernate: select basket0_.id as id1_0_0_, basket0_.capacity as capacity2_0_0_ from basket basket0_ where basket0_.id=?
Hibernate: select basket0_.id as id1_0_0_, basket0_.capacity as capacity2_0_0_ from basket basket0_ where basket0_.id=?
1
Rafał Pydyniak