a. Sesion
b. Transaction
FetchType.LAZY는 지연로딩 방식으로 엔티티의 연관 관계를 필요할 때 로드하도록 설정하는 것을 말하며 하나의 쿼리로 주 엔티티를 조회한 후 연관된 엔티티를 각각 조회하기 위해 추가로 N개의 쿼리가 발생하는 것을 N+1 문제라고 한다.
예시로 설명
상황: Memeber 엔티티와 Team 엔티티가 다대일 관계를 가지고 있다고 가정
Member 엔티티는 여러 명의 회원,Team 엔티티는 각 회원이 속한 팀을 나타냄
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
}
@Entity
public class Team {
@Id
@GeneratedValue
private Long id;
private String name;
}
문제 발생 시나리오:
Member 엔티티 리스트를 조회하는 JPQL 쿼리를 실행
List<Member> members = entityManager.createQuery("SELECT m FROM Member m", Member.class).getResultList();```
이 쿼리로 인해 회원 데이터를 조회하는 쿼리가 실행
예를 들어, 10명의 Member가 조회되었다면
SELECT * FROM Member;
이후, 각 Member 엔티티의 Team 필드가 사용될 때마다 추가적으로 Team 엔티티를 조회하는 쿼리가 실행
sql
SELECT * FROM Team WHERE id = ?; -- 첫 번째 회원의 팀 조회
SELECT * FROM Team WHERE id = ?; -- 두 번째 회원의 팀 조회
...
SELECT * FROM Team WHERE id = ?; -- 열 번째 회원의 팀 조회```
결과적으로, 1개의 메인 쿼리 + 10개의 추가 쿼리로 총 11개의 쿼리가 실행되며 N+1 문제가 나타남
해결 방법
FetchType.EAGER로 설정: 연관된 엔티티를 즉시 로딩하여 Member 를 조회할 때 Team 엔티티도 함께 조회한다. 하지만, 무조건 즉시 로딩을 사용하는 것은 성능 문제를 야기할 수 있다.
@EntityGraph() 사용: JPQL 쿼리 실행 시점에 즉시 로딩을 적용
@EntityGraph(attributePaths = {"team"})
List<Member> findAllWithTeam();
Join Fetch 사용: JPQL에서 Join Fetch를 사용하여 N+1 문제를 해결
List<Member> members = entityManager.createQuery(
"SELECT m FROM Member m JOIN FETCH m.team", Member.class).getResultList();
JPA에서 Entity를 캐시하는 방법은 무엇인가요?

위에 이미지처럼 find를 했을 때 해당 엔티티가 1차 캐시에 존재하면 1차 캐시에 저장된 엔티티를 반환하고 존재하지 않으면 DB를 조회한다.
