@OneToMany 에서 많이 일어난다.@Entity
public class User {
@Id
@GeneratedValue
private long id;
private String firstName;
private String lastName;
@ManyToOne(fetch = FetchType.EAGER) // 즉시 로딩
@JoinColumn(name = "team_id", nullable = false)
private Team team;
}
@Entity
public class Team {
@Id
@GeneratedValue
private long id;
private String name;
// 여기 이 부분 !!
@OneToMany(fetch = FetchType.EAGER)
private List<User> users = new ArrayList<>();
}
teamRepository.findAll();
// team
Hibernate: select team0_.id as id1_0_, team0_.name as name2_0_ from team team0_
Hibernate: select users0_.team_id as team_id1_1_0_, users0_.users_id as users_id2_1_0_, user1_.id as id1_2_1_, user1_.first_name as first_na2_2_1_, user1_.last_name as last_nam3_2_1_, user1_.team_id as team_id4_2_1_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id=?
Hibernate: select users0_.team_id as team_id1_1_0_, users0_.users_id as users_id2_1_0_, user1_.id as id1_2_1_, user1_.first_name as first_na2_2_1_, user1_.last_name as last_nam3_2_1_, user1_.team_id as team_id4_2_1_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id=?
Hibernate: select users0_.team_id as team_id1_1_0_, users0_.users_id as users_id2_1_0_, user1_.id as id1_2_1_, user1_.first_name as first_na2_2_1_, user1_.last_name as last_nam3_2_1_, user1_.team_id as team_id4_2_1_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id=?
Hibernate: select users0_.team_id as team_id1_1_0_, users0_.users_id as users_id2_1_0_, user1_.id as id1_2_1_, user1_.first_name as first_na2_2_1_, user1_.last_name as last_nam3_2_1_, user1_.team_id as team_id4_2_1_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id=?
findAll()을 한 순간 select t from Team t 라는 JPQL 구문이 생성되고 해당 구문을 분석한 select * from team 이라는 SQL이 생성되어 실행된다.
DB 의 결과를 받아 team Entity의 인스턴스들을 생성한다.
team과 연관되어 있는 user도 로딩을 해야 한다.
영속성 컨텍스트에서 연관된 user가 있는지 확인한다.
영속성 컨텍스트에 없다면 2에서 만들어진 team인스턴스들 개수에 맞게 select * from user where team_id = ? 이라는 SQL 구문이 생성된다. (N+1 발생)
findAll() 을 한 순간 select t from Team t 이라는 JPQL 구문이 생성되고 해당 구문을 분석한 select * from team 이라는 SQL이 생성되어 실행된다. 2 에서 만들어진 team 인스턴스들 개수에 맞게 select * from user where team_id = ? 이라는 SQL 구문이 생성된다. (N+1 발생)public interface TeamRepository extends JpaRepository<Team, Long> {
@Query("select t from Team t join fetch t.users")
List<Team> findAllFetchJoin();
}
Hibernate: select team0_.id as id1_0_0_, user2_.id as id1_2_1_, team0_.name as name2_0_0_, user2_.first_name as first_na2_2_1_, user2_.last_name as last_nam3_2_1_, user2_.team_id as team_id4_2_1_, users1_.team_id as team_id1_1_0__, users1_.users_id as users_id2_1_0__ from team team0_ inner join team_users users1_ on team0_.id=users1_.team_id inner join user user2_ on users1_.users_id=user2_.id
@Entitygraph@Entitygraph 의 attributePaths 에 쿼리 수행 시 바로 가져올 필드명을 지정하면 Lazy가 아닌 Eager 조회로 가져오게 됨.
Fetch Join 과 동일하게 JPQL 을 사용하여 쿼리문을 작성하고 필요한 연관관계를 Entitygraph 에 설정하면 된다.
Fetch Join 과는 다르게 Outer Join 으로 실행된다.
@EntityGraph(attributePaths = "users")
@Query("select t from Team t")
List<Team> findAllEntityGraph();
spring:
jpa:
properties:
hibernate:
default_batch_fetch_size: 1000
Hibernate: select team0_.id as id1_0_, team0_.name as name2_0_ from team team0_
Hibernate: select users0_.team_id as team_id1_1_1_, users0_.users_id as users_id2_1_1_, user1_.id as id1_2_0_, user1_.first_name as first_na2_2_0_, user1_.last_name as last_nam3_2_0_, user1_.team_id as team_id4_2_0_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id in (?, ?, ?, ?)