
JPQL
JPA용 쿼리 언어로 SQL과 비슷하나 Entity를 대상으로 하는 점이 다르다
문자열로 쿼리가 작성되므로 컴파일 에러로 검출 할 수가 없다
너무나 복잡한 수가 필요시 nativeQuery 값을 조절하여 순수 SQL 사용이 가능하다
일반적인 복잡한 예시를 가져올 때 사용한다
(어떤 조건이 몇 이상이고 이름이 어떤 것이고, 기간은 일주일 이내 검색된 데이터 색출)
(이런 경우는 일반 JPA 메서드 쿼리 기능으로는 가져오는 것이 어려움)
예시
멤버 테이블과 팀에 대한 테이블이 있고
팀 속에 멤버가 포함되는 구조의 테이블이 있다고 가정
이 중에 나이가 20 이상인 전체 팀원 정보와 그들이 속한 팀 정보를 검색하려한다
일반 SQL 시
SELECT
m.id,
m.name,
m.age,
t.name as team_name
FROM members m
LEFT JOIN teams t ON m.team_id = t.id
WHERE m.age >= 20;JPQL 활용 시
// Repository 부분에 따로 선언
@Query("""
SELECT m
FROM Member m
LEFT JOIN m.team t
WHERE m.age >= 20
""")
List<Member> findOlderMembers();차이점
Entity를 대상으로 하고 있어
연관관계만 표시하지 따로 ON 조건인 연관되는 필드를 명시하지 않음
기본 문법
SELECT
SQL
--1)
SELECT * FROM members;
--2)
SELECT name FROM members;JPQL
//1)
@Query("SELECT m FROM Member m")
List<Member> findAll();
//2)
@Query("SELECT m.name FROM Member m")
List<String> findAllName();
// DTO 활용 조회
@Query("""
SELECT new com.example.dto.MemberDto(m.name, m.age)
FROM Member m
""")
List<MemberDto> findAllDto();WHERE
SQL 과 사용법 자체는 다르지 않지만 파라미터 대입은 다름
@Query 절의 파라미터 대입의 이름과 같게 @Param 선언이 필요함
JPQL
// 파라미터의 이름과 일치하도록 @Param에 선언하여 사용
@Query("SELECT m FROM Member m WHERE m.name = :name")
List<Member> findByName(@Param("name") String name);JOIN
Entity의 연관관계를 활용하므로 따로 컬럼을 기재하지 않음
(다만 JPA 2.1 이상부터는 ON 절 사용 가능함)
따로 FK에 대해 어떠한 관계도 없다면 사용이 불가함
(일반적인 상황에서만, JPA 2.1 부터 ON 절 기재가 가능해서
괜찮긴 하나 Fetch Join이 안됨)
(N+1 문제 발생 여지)
이러한 경우엔 nativeQuery = true 로 사용하던지
ConstraintMode 를 조절해서 NO_CONSTRAINT 로 사용해야함
JPQL
// 기본 JOIN
@Query("SELECT m FROM Member m JOIN m.team t WHERE t.name = :teamName")
List<Member> findByTeamName(@Param("teamName") String teamName);
// Fetch Join
@Query("SELECT m FROM Member m JOIN FETCH m.team")
List<Member> findAllWithTeam();
// 실행되는 SQL:
// SELECT m.*, t.*
// FROM members m
// INNER JOIN teams t ON m.team_id = t.id;
// LEFT JOIN
@Query("SELECT m FROM Member m LEFT JOIN FETCH m.team")
List<Member> findAllWithTeamLeftJoin();
// ========== JPA 2.1+ ON 절 지원 ==========
@Query("""
SELECT m
FROM Member m
LEFT JOIN Team t ON m.teamId = t.id
WHERE t.name = :teamName
""")
List<Member> findByTeamNameOn(@Param("teamName") String teamName);
// 실행 SQL:
// SELECT m.*
// FROM members m
// LEFT JOIN teams t ON m.team_id = t.id
// WHERE t.name = ?
// 여러개 Fetch JOIN
@Query("""
SELECT DISTINCT m
FROM Member m
LEFT JOIN FETCH m.team
LEFT JOIN FETCH m.orders
""")
List<Member> findAllWithTeamAndOrders();nativeQuery 를 사용 할 때 주의 할 점
사용 하기 전에 영속성 컨텍스트를 사용하는 부분이 있었다면 flush 해야한다
nativeQuery 를 사용할 때와 다르게 자동으로 flush 처리해주지 않기 때문에!