
기존 SQL
SELECT * FROM employee WHERE name = 'KIM';
JPQL
SELECT e FROM Employee e WHERE e.name = :name
- 레포지토리 메소드 위에 붙여서 직접 쿼리문을 작성할 때 사용
- SQL처럼 보이지만, 테이블명과 컬럼명이 아니라 엔티티명과 필드명을 사용
- 대소문자 주의 (엔티티명, 필드명은 자바 코드 기준으로 정확히 써야 한다.
- 메소드 이름이 너무 길어지는 걸 막을 수 있다.
- JOIN, GROUP BY, HAVING 같은 복잡한 조회도 작성할 수 있다.
예시
@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
@Query("SELECT m FROM Member m WHERE m.name = :name")
List<Member> findMember(@Param("name") String name);
@Query("SELECT m FROM Member m WHERE m.name = :name AND m.email = :email")
List<Member> findMember(@Param("name") String name, @Param("email") String email);
@Query("""
SELECT m.name, m.email, COUNT(a.articleId) as count
FROM Member m LEFT JOIN Article a ON a.member = m
GROUP BY m
ORDER BY count DESC
""")
List<Object[]> getMemberStatsObject();
}
데이터 삭제, 변경
@Query, @Modifying 어노테이션 사용
이때, 영속성 컨텍스트 @Transactional 사용 권장
네이티브 SQL 쿼리
특정 DB에만 지원하는 SQL명령이 필요한 경우 @Query 어노테이션의 nativeQuery 속성값을 true로 설정하여 JPQL 대신 데이터베이스에서 사용 가능한 SQL 명령 매핑
LazyInitializationException: 연관된 데이터를 나중에 가져와야 하는데 그 시점에 DB와 연결된 작업 구간이 끝나 있으면 가지고 올 수 없음
- 해결방안: 메소드에 @Transactional 어노테이션 사용, 혹은 DTO 객체로 변환하여 사용
N+1: 데이터 여러 개를 조회한 뒤 연관 데이터까지 하나씩 꺼내다가 쿼리가 너무많이 나가는 문제
- 해결방안:
Fetch Join (일반적)
@EntityGraph 어노테이션
부트설정 파일에서 Batch Size 설정하여 설정한 크기만큼 묶어서 데이터를 조회하는 방식
ex)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;