List<Member> result = em.createQuery(
"select m From Member m where m.username like '%kim%",
Member.class)
.getResultList();
//member 엔티티 자체를 조회해오라는 의미
//단점 : 동적쿼리를 만들기 어렵다.
//String sqlString = "select m From Member m" + String where = "where m.username like '%kim%' 이렇게 하기 어려움
//2.Criteria(망한 스펙, 실무에서 사용하지 않는 스펙)
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Member> query = cb.createQuery(Member.class);
//Member에서
Root<Member> m = query.from(Member.class);
//m을 select, m의 username이 kim인 것을 추출
CriteriaQuery<Member> cq = query.select(m).where(cb.equal(m.get("username"), "kim"));
List<Member> resultList = em.createQuery(cq).getResultList();
//장점 : 동적쿼리가 가능/sql 작성을 올바르게 작성해주도록 컴파일시점에 오타를 잡아준다.
//단점 : sql 스럽지 않다. 실무에서는 안쓴다. 유지보수가 어렵다.
//4. 네이티브 SQL(잘 안씀)
em.createNativeQuery(
"select MEMBER_ID, city, street. zipcode, USERNAME from MEMBER"
).getResultList();
//5. JDBC
//조심해야할 점 : 영속성 컨텍스트는 플러시가 되어야 db에 데이터가 있다.
//(AUTO전략)flush되는 시점 : commit되기 전, query날아가기 전에 동작
// => flush되면 DB에 적용된다.
//예
Member member = new Member();
member.setUsername("member1");
em.persist(member);
//이 시점에 em.flush()가 자동으로 날아가 DB에 insert해준다.
//1번의 경우
List<Member> resultList1 = em.createNativeQuery(
"select MEMBER_ID, city, street, zipcode FROM MEMBER"
).getResultList();
// 반면 JDBC는 jpa가 아니므로 다음과 같이 작성해준다면
//em.flush() x -> DB에 값이 없다. , 오류 발생
//수동으로 em.flush() 작서해야 한다.
//2번의 경우
//dbconn.executeQuery("select * from member");
JPQL은 객체지향 쿼리 언어다.따라서 테이블을 대상으로 쿼리를 날리는 것이 아니라 엔티티 객체를 대상
으로 쿼리한다
JPQL은 결국 SQL로 변환된다
엔티티와 속성은 대소문자 구분O (Member, age)
JPQL 키워드는 대소문자 구분X (SELECT, FROM, where)
엔티티 이름 사용, 테이블 이름이 아님(Member)
별칭은 필수(m) (as는 생략가능)
예) select m from Member as m where m.age > 18
Member member = new Member();
member.setUsername("member1");
em.persist(member);
//반환 타입이 명확할때 사용 :: TypedQuery<제네릭>
TypedQuery<Member> query = em.createQuery("" +
"SELECT m FROM Member m", Member.class);
TypedQuery<String> query1 = em.createQuery(
"SELECT m.username FROM Member m", String.class
);
//반환타입이 명확하지 않을 때 사용 :: Query
Query query2 = em.createQuery(
"SELECT m.username, m.age FROM Member m"
);
Member member = new Member();
member.setUsername("member1");
em.persist(member);
//반환 타입이 명확할때 사용 :: TypedQuery<제네릭>
TypedQuery<Member> query = em.createQuery(
"SELECT m FROM Member m WHERE m.username = :username", Member.class);
//파라미터 바인딩- 이름기준일때
query.setParameter("username", "member1");
Member singleResult = query.getSingleResult();
System.out.println("singleResult = "+singleResult);
//파라미터 바인딩-위치기준(추천 X)
tx.commit();
Member member = new Member();
member.setUsername("member1");
member.setAge(10);
em.persist(member);
em.flush();
em.clear();
//1. 엔티티 프로젝션
List<Member> result = em.createQuery(
"SELECT m FROM Member m", Member.class
).getResultList();
Member findMember = result.get(0);
findMember.setAge(20);
//UPDATE쿼리 발생..JPA에 의해 관리됨을 알 수 있다.
//2. 엔티티 프로젝션
List<Team> result2 = em.createQuery(
"SELECT t FROM Member m JOIN m.team t", Team.class
).getResultList();
//Member객체에 Team이 포함되어있어도 이렇게 해서 team과 조인하도록 작성 추천
//쿼리 날아가는 것도 확인해보면 join됨을 알 수 있다.
//3. 임베디드 타입 프로젝션
em.createQuery(
"SELECT o.address FROM Order o", Address.class
).getResultList();
SELECT m.username, m.age FROM Member m
[프로젝션 - 여러값을 조회하는 경우 총 3가지]
예) SELECT m.username, m.age FROM Member m
(1) Query 타입으로 조회
//4. 스칼라 타입 프로젝션
//(1) Query타입으로 조회하는 경우
List resultList = em.createQuery(
"select m.username, m.age from Member m"
).getResultList();
Object o = resultList.get(0);
Object[] result3 = (Object[]) o;
System.out.println("username = "+result3[0]);
System.out.println("age = "+result3[1]);
(2) Object[] 타입으로 조회
//(2) Object[] 타입으로 조회하는 경우
List <Object[]> resultList1 = em.createQuery(
"select m.username, m.age from Member m"
).getResultList();
Object[] result4 = resultList1.get(0);
System.out.println("username = "+result4[0]);
System.out.println("age = "+result4[1]);
(3) new 명령어로 조회
//(3) new 명령어로 조회하는 경우
List<MemberDTO> resultList2 = em.createQuery(
"select new hellojpa.MemberDTO(m.username, m.age) from Member m"
, MemberDTO.class
).getResultList();
MemberDTO memberDTO = resultList2.get(0);
System.out.println("username :: "+memberDTO.getUsername());
1) setFirstResult(int startPosition) : 조회 시작 위치
(0부터 시작)
2) setMaxResults(int maxResult) : 조회할 데이터 수
for(int i=0;i<100;i++) {
Member member = new Member();
member.setUsername("member"+(i+1));
member.setAge(i);
em.persist(member);
}
em.flush();
em.clear();
List<Member> resultList2 = em.createQuery(
"select m from Member m order by m.age desc"
, Member.class
).setFirstResult(0) //0부터 시작해서
.setMaxResults(10) //10개까지 가져온다.
.getResultList();
System.out.println("size : "+ resultList2.size());
for(Member m : resultList2){
System.out.println(m);
}
tx.commit();
이렇게 하면 다음의 결과를 얻게 된다.
Hibernate:
/* select
m
from
Member m
order by
m.age desc */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.TEAM_ID as TEAM_ID4_0_,
member0_.username as username3_0_
from
Member member0_
order by
member0_.age desc limit ?
size : 10
Member{id=100, username='member100', age=99}
Member{id=99, username='member99', age=98}
Member{id=98, username='member98', age=97}
Member{id=97, username='member97', age=96}
Member{id=96, username='member96', age=95}
Member{id=95, username='member95', age=94}
Member{id=94, username='member94', age=93}
Member{id=93, username='member93', age=92}
Member{id=92, username='member92', age=91}
Member{id=91, username='member91', age=90}
1) 내부조인
String query = "select m from Member m inner join m.team t";
2) 외부조인
String query2 = "select m from Member m left outer join m.team t";
3) 세타조인
String query3 = "select m from Member m, Team t where m.username = t.name";
1) 조인대상 필터링
String query4 = "select m from Member m left join m.team t on t.name = 'teamA'";
2) 연관관계 없는 엔티티 외부 조인
String query5 = "select m from Member m left join Team t on m.username = t.name";
• [NOT] EXISTS (subquery): 서브쿼리에 결과가 존재하면 참
예) select m from Member m
where exists (select t from m.team t where t.name = ‘팀A')
• {ALL | ANY | SOME} (subquery)
• ALL 모두 만족하면 참
예) 전체 상품 각각의 재고보다 주문량이 많은 주문들
select o from Order o
where o.orderAmount > ALL (select p.stockAmount from Product p)
• ANY, SOME: 같은 의미, 조건을 하나라도 만족하면 참
예) 어떤 팀이든 팀에 소속된 회원
select m from Member m
where m.team = ANY (select t from Team t)
• [NOT] IN (subquery): 서브쿼리의 결과 중 하나라도 같은 것이 있으면 참
타입 표현은 아래와 같이 JPQL문에 함께 작성할 수 있다.
• 문자: ‘HELLO’, ‘She’’s’
• 숫자: 10L(Long), 10D(Double), 10F(Float)
• Boolean: TRUE, FALSE
• ENUM: jpabook.MemberType.Admin (패키지명 포함)
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member();
member.setUsername("member1");
member.setAge(10);
member.setMemberType(MemberType.ADMIN);
member.changeTeam(team);
em.persist(member);
em.flush();
em.clear();
//파라미터 바인딩하지 않은 경우
String query = "select m.username, 'HELLO', true from Member m "+
"where m.type = hellojpa.MemberType.USER";
//파라미터 바인딩을 한 경우
String query2 = "select m.username, 'HELLO', true from Member m "+
"where m.type = :usertype";
List<Object[]> result = em.createQuery(query)
.getResultList();
List<Object[]> result2 = em.createQuery(query2)
.setParameter("usertype", MemberType.ADMIN)
.getResultList();
for(Object[] objects: result){
System.out.println("objects = "+objects[0]);
System.out.println("objects = "+objects[1]);
System.out.println("objects = "+objects[2]);
}
@Enumerated(EnumType.STRING)
으로 문자열 전략을 사용@Enumerated(EnumType.STRING)
private MemberType type;
package hellojpa;
public enum MemberType {
ADMIN, USER
}
1) 기본 CASE식
select case when m.age <= 10 then '학생요금' when m.age >= 60 then '경로요금' else '일반요금' end from Member m
2) 단순 CASE식
select case t.name when '팀A' then '인센티브110%' when '팀B' then '인센티브120%' else '인센티브105%' end from Team t
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member();
member.setUsername("관리자");
member.setAge(10);
member.setMemberType(MemberType.ADMIN);
member.changeTeam(team);
em.persist(member);
em.flush();
em.clear();
String query = "select NULLIF(m.username, '관리자') from Member m";
List<String> resultList = em.createQuery(query, String.class).getResultList();
for(String s : resultList){
System.out.println(s);
}
null이 출력된다.