@Fetch(FetchMode.JOIN)
また、JPA を使用している場合は作業できませんでしたが(休止状態の Criteria API を使用している場合は正常に動作します)、理由を説明する例も見つかりませんでしたが、いくつかの回避策を考えることができます。
グループを熱心にロードする最も簡単な方法は、JPQL を使用することです。
public interface PersonRepository extends JpaRepository<Person, String>{
@Query(value = "select distinct p from Person p left join fetch p.groups")
List<Person> getAllPersons();
}
spring-data-jpa を使用しているため、 を使用してグループを熱心にロードすることもできますSpecification
。(1.4.x 以降では、null を返す仕様をチェーンできます)。
final Specification<Person> fetchGroups = new Specification<Person>() {
@Override
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
root.fetch("groups", JoinType.LEFT);
query.distinct(true);
return null;
}
};
これらのいずれも選択できない場合、最善の策はおそらく を使用すること@Fetch(FetchMode.SUBSELECT)
です。
@Fetch(FetchMode.SELECT)
と組み合わせて使うのも一つの手@BatchSize
です。@BatchSize
n+1 クエリの問題を解決するのに役立ちます。バッチ サイズを微調整することで、実行されるクエリの量を CEIL(n/batch_size)+1 に減らすことができます。
@Entity
@Table(name = "persons")
public class Person {
@Id
String name;
@ManyToMany(fetch = FetchType.EAGER)
@BatchSize(size = 20)
Set<Group> groups = new HashSet<>();
}
@Entity
@Table(name = "groups")
public class Group {
@Id
String name;
@ManyToMany(mappedBy = "groups", fetch = FetchType.LAZY)
Set<Person> persons = new HashSet<>();
}
public interface PersonRepository extends JpaRepository<Person, String>{}
personRepository.findAll();
このマッピングは、 10 人を含み、5 に設定されたデータベースで実行すると、次の sql になります@BatchSize
。
Hibernate:
select
person0_.name as name1_
from
persons person0_
Hibernate:
select
groups0_.persons_name as persons1_1_1_,
groups0_.groups_name as groups2_1_,
group1_.name as name0_0_
from
persons_groups groups0_
inner join
groups group1_
on groups0_.groups_name=group1_.name
where
groups0_.persons_name in (
?, ?, ?, ?, ?
)
Hibernate:
select
groups0_.persons_name as persons1_1_1_,
groups0_.groups_name as groups2_1_,
group1_.name as name0_0_
from
persons_groups groups0_
inner join
groups group1_
on groups0_.groups_name=group1_.name
where
groups0_.persons_name in (
?, ?, ?, ?, ?
)
@BatchSize
でマップされたコレクションでも機能することに注意してくださいFetchType.LAZY
。