📦
@BatchSize
- 지연 로딩 시 연관 엔티티를 여러 개씩 묶어(IN 쿼리) 한 번에 조회하도록 하는 설정
- “엔티티 1개 접근마다 1쿼리” → “여러 키를 IN으로 묶은 1쿼리”로 N+1 완화
💡 왜 사용할까?
fetch join은 페이징 불가(DB 레벨 반영 X → 메모리 페이징) → OOM 위험 ⚠️@BatchSize는 지연 로딩을 유지하면서도🛠️ 어떻게 사용할까?
@BatchSize(size = 100)
@OneToMany(mappedBy = "company")
private List<Tutor> tutorList;
where tutor.company_id in (?, ?, ...) 형태로 한 방에 가져옴📎 예시 코드 및 실행 흐름
String query = "select c from Company c";
List<Company> companyList = em.createQuery(query, Company.class)
.setFirstResult(0)
.setMaxResults(2)
.getResultList();
System.out.println("companyList.size() = " + companyList.size());
for (Company company : companyList) {
System.out.println("company.getName() = " + company.getName());
for (Tutor tutor : company.getTutorList()) {
System.out.println("tutor.getName(): " + tutor.getName());
}
}
@Entity
@Table(name = "company")
public class Company {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@BatchSize(size = 100)
@OneToMany(mappedBy = "company")
private List<Tutor> tutorList = new ArrayList<>();
public Company() {
}
public Company(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public List<Tutor> getTutorList() {
return tutorList;
}
}
select c from Company c + 페이징(예: 0~1) → sparta, etc 두 건만 우선 로드
각 회사의 tutorList 접근 시
Company마다 별도 쿼리 실행 (N+1)Company의 Tutor를 동시에 로드🧭
fetch joinvs@BatchSize
| 항목 | fetch join | @BatchSize |
|---|---|---|
| 목적 | 즉시 함께 로드(한 번의 SQL) | 지연 시 여러 건 묶어 로드(IN) |
| 적용 대상 | N:1, 1:1, (1:N은 중복·페이징 제약) | 주로 컬렉션(1:N), 엔티티 참조에도 적용 가능 |
| 페이징 | 1:N 컬렉션에선 불가(메모리 페이징) | 가능(지연 로딩 유지) |
| 중복/결과 | 조인으로 중복 행 가능, DISTINCT 필요 | 중복 없음(컬렉션 지연 로딩 시 개별 조회) |
| 장점 | N+1 즉시 해소, 조회 한 번에 그래프 완성 | 쿼리 수 감소, OOM 방지에 유리 |
| 권장 사용 | N:1 조회 최적화 | 1\:N + 페이징 시 대안 |
🧠 요약 정리
✅ @BatchSize 핵심
📝 주의(이름 혼동 포인트)
hibernate.default_batch_fetch_size를 사용함hibernate.jdbc.batch_size는INSERT/UPDATE 같은 DML 배치 설정에 쓰이는 이름이라 혼동 주의해야 함🔚 fetch join 총정리
개념: 연관 엔티티/컬렉션을 한 쿼리로 함께 로드
fetch join이 우선효과: N+1 해결 가능
주의: 중복 발생 시 DISTINCT (Hibernate 6+ 일부 자동)
1:N 컬렉션 + 페이징: DB 페이징 불가 → 메모리 페이징(OOM 위험)
fetch join 지양 + @BatchSize로 지연 로딩 최적화복잡 조회: 일반 JOIN으로 필요한 필드만 뽑아 DTO 반환(JPQL/QueryDSL)