概要
Spring Data JPAでfindAll()
、findById(id)
実行時にJOINさせるようにし、N+1問題が起きないようにする。
JPQLは使わないで実現する。
Service
以下のようにそれぞれを呼び出す。以下の例ではpagingを実装しているが、していない場合でも同じ。
UserService
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository UserRepository;
public Page<UserModel> findAll() {
// paging
Pageable limit = PageRequest.of(0, 10);
return UserRepository.findAll(limit);
}
public Optional<UserModel> findById(Long id) {
return UserRepository.findById(id);
}
}
UserModel
findById()
をjoinさせるためには、 @Fetch(FetchMode.JOIN)
アノテーションを付与すればOK。
findAll()
は、@NamedEntityGraph
を使う。nameには任意の名前を定義する。
UserModel
@Entity
@Getter
@Table(name = "users")
@NamedEntityGraph(
name = "group_with_all_associations",
includeAllAttributes = true
)
public class UserModel {
@Id
private Long id;
@Column(name = "user_name")
private String userName;
@Column(name = "group_id")
private Long groupId;
@ManyToOne
@JoinColumn(name = "group_id", referencedColumnName = "id")
@Fetch(FetchMode.JOIN)
private GroupModel groupModel;
}
GroupModel
こちらは特筆すべきことはなし。
GroupModel
@Entity
@Getter
@Table(name = "groups")
public class GroupModel {
@Id
private Long id;
@Column(name = "group_name")
private String groupName;
}
UserRepository
UserModelの@NamedEntityGraph
のnameの値を、以下のように@EntityGraph
のvalueに定義する。
これでfindAll()
もjoinされる。
UserRepository
public interface UserRepository extends JpaRepository<UserModel, Long> {
@EntityGraph(value = "group_with_all_associations", type = EntityGraph.EntityGraphType.FETCH)
public Page<UserModel> findAll(Pageable limit);
}
発行されるSQLを確認
実行して、発行されるSQLを確認する。
SQLのログを出力
SQLのログが出力されるようにする。
application.yml
logging:
level:
org:
hibernate:
SQL: DEBUG
type:
descriptor:
sql:
BasicBinder: TRACE
findAll()
select
usermo0_.id as id1_1_0_,
usermo0_.group_id as group_i49_1_0_,
groupmodel1_.id as id1_0_1_,
groupmodel1_.group_name as group_n17_0_1_
from
users usermo0_
left outer join
groups groupmodel1_
on usermo0_.group_id = groupmodel1_.id
limit ?
findById()
select
usermo0_.id as id1_1_0_,
usermo0_.group_id as group_i49_1_0_,
groupmodel1_.id as id1_0_1_,
groupmodel1_.group_name as group_n17_0_1_
from
users usermo0_
left outer join
groups groupmodel1_
on usermo0_.group_id = groupmodel1_.id
where
usermo0_.id = ?