가장 단순한 조회 방법
JPA를 사용하면 엔티티 객체를 중심으로 개발
검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색
모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능
필요한 데이터만 DB에서 불러오려면 검색 조건이 포함된 SQL이 필요
SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어 제공
SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 지원
JPQL은 엔티티 객체를 대상으로 쿼리
SQL은 데이터베이스 테이블 대상으로 쿼리
문자가 아닌 자바코드로 JPQL 작성가능
JPQL 빌더 역할, JPA 공식 기능
너무 복잡하고 실용성이 없는 단점 존재
QueryDSL 권장!
문자가 아닌 자바코드로 JPQL 작성가능
JPQL 빌더 역할
컴파일 시점에 문법 오류 찾을 수 있음
단순하고 쉬워서 동적쿼리 작성 편하다(실무 사용 권장)
JPA가 제공하는 SQL을 직접 사용하는 기능
JPQL로 해결할 수 없는 특정 데이터베이스에 의존적인 기능
ex) 오라클 CONNECT BY, 특정 DB만 사용하는 SQL 힌트
Member member = new Member();
member.setUsername("member1");
member.setAge(10);
em.persist(member);
TypedQuery<Member> query1 = em.createQuery("select m from Member m", Member.class);
List<Member> members = query1.getResultList();
for (Member member1 : members) {
System.out.println("members usernames = "+ member1.getUsername());
}
----------------------------------------------------------------------------
TypedQuery<Integer> query2 = em.createQuery("select m.age from Member m", Integer.class);
int age = query2.getSingleResult();
System.out.println("age = "+ age);
---------------------------------------------------------------------------
// select m from Member m where m.username = :username 도 가능
Member result = em.createQuery("select m from Member m where m.username = ?1", Member.class)
.setParameter(1, "member1")
.getSingleResult();
System.out.println("result = "+result.getUsername());
SELECT 절에 조회할 대상을 지정하는 것
대상 : 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자 등 기본 데이터 타입)
Distinct로 중복 제거
Select m From Member m -> 엔티티 프로젝션
Select m.team From Member m -> 엔티티 프로젝션
Select m.address From Member m -> 임베디드 타입 프로젝션
Select m.username, m.age From Member m -> 스칼라 타입 프로젝션
// 엔티티 프로젝션은 전부 다 영속성 컨텍스트에 관리됨
List<Member> result = em.createQuery("select m from Member m", Member.class)
.getResultList();
Member findMember = result.get(0);
findMember.setAge(20);
----------------------------------------------------------------------------
// 둘 다 inner join으로 쿼리가 나가는데 이런 방식은 별로 좋지 않음(묵시적 조인)
List<Team> result = em.createQuery("select m.team from Member m ", Team.class)
.getResultList();
// JPQL도 쿼리 나가는 것과 비슷하게 써줘야 됨. 성능에 영향을 줄 수 있는 요소가 많기 때문(명시적 조인)
List<Team> result = em.createQuery("select t from Member m join m.team t", Team.class)
.getResultList();
----------------------------------------------------------------------------
// 한계 - select address from Address o 는 안됨(소속되어 있기 때문)
em.createQuery("select o.address from Order o", Address.class)
.getResultList();
----------------------------------------------------------------------------
// 일반 SQL과 가장 흡사
em.createQuery("select distinct m.username, m.age from Member m")
.getResultList();
List resultList = em.createQuery("select distinct m.username, m.age from Member m")
.getResultList();
Object o = resultList.get(0);
Object[] result = (Object[]) o;
----------------------------------------------------------------------------
List<Object[]> resultList = em.createQuery("select distinct m.username, m.age from Member m")
.getResultList();
Object[] result = resultList.get(0);
System.out.println("username = "+ result[0]);
System.out.println("age = "+ result[1]);
List<MemberDTO> result = em.createQuery("select new jpql.MemberDTO(m.username, m.age) from Member m", MemberDTO.class)
.getResultList();
MemberDTO memberDTO = result.get(0);
System.out.println("memberDTO username = "+ memberDTO.getUsername());
System.out.println("memberDTO age = "+ memberDTO.getAge());
JPA는 페이징을 두 API로 추상화
List<Member> result = em.createQuery("select m from Member m order by m.age desc", Member.class)
.setFirstResult(1)
.setMaxResults(10)
.getResultList();
페이징 쿼리
Select m from Member m [INNER] Join m.team t;
Select m from Member m LEFT[OUTER] Join m.team t;
Select count(m) from Member m, Team t where m.team = t.id";
// 회원과 팀을 조인하면서, 팀 이름이 A인 팀만 조인
// JPQL
select m, t from member m Left Join m.team t on t.name = 'A';
// SQL
select m.*, t.* from member m Left Join Team t ON m.team_id = t.id and t.name = 'A';
// 회원의 이름과 팀의 이름이 같은 대상 외부 조인
// JPQL
select m, t from member m Left Join Team t ON m.team = t.id";
//SQL
select m.*, t.* from member m Left Join Team t ON m.team = t.id";
where, having 절에서만 서브쿼리 사용 가능
select 절에서도 능
한계
from 절의 서브쿼리는 현재 JPQL에서 불가능
String query = "select mm.age, mm.username
from (select m.age, m.username from Member m) as mm";
대안
조인으로 풀 수 있으면 풀어서 해결
문자 - 'HELLO', 'She''s'
숫자 - 10L(Long), 10D(Double), 10F(Float)
Boolean - True, False
ENUM - jpabook.MemberType.Admin(패키지명 포함)
엔티티 타입 - TYPE(m) = Member(상속관계에서 사용)
표준 SQL 다 지원한다고 보면 됨
기본
select
case when m.age <= 10 then '학생요금'
when m.age >= 60 then '경로요금'
else '일반요금'
end
from Member m
COALESCE - 하나씩 조회해서 null이 아니면 반환
NULLIF - 두 값이 같으면 null 반환, 다르면 첫번째 값 반환
select coalesce(m.username, '이름 없는 회원') from Member m
select nullif(m.username, '관리자') from Member m
표준함수(데이터베이스와 관계없이 쓰면 됨)
사용자 정의 함수
데이터 베이스 방언에 추가해야 함
select function('group_concat', i.name) from Item i;