실무에서 거의 대부분이 JPA로 해결이 가능하고 나머지를 나는 MyBatis등으로 사용하면 좋을 거 같다.
단 영속성 컨텍스트를 적절한 시점에 강제로 플러시 필요, JPA만 인식할 수 있는 영역에서 DB영역으로 보내야
함께 조화를 이룰 수 있음.
결론적으로 단점은 너무 복잡해서 유지보수가 어렵고 실용성이 없다.
따라서 동적쿼리에 대해서 Criteria 대신에 QueryDSL 사용 권장. 한 마디로 망한 스펙.
//Criteria 사용 준비
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Member> query = cb.createQuery(Member.class);
//루트 클래스 (조회를 시작할 클래스)
Root<Member> m = query.from(Member.class);
//쿼리 생성 CriteriaQuery<Member> cq =
query.select(m).where(cb.equal(m.get("username"), “kim”));
List<Member> resultList = em.createQuery(cq).getResultList();
JPAFactoryQuery query = new JPAQueryFactory(em);
QMember m = QMember.member;
List<Member> list =
query.selectFrom(m)
.where(m.age.gt(18))
.orderBy(m.name.desc())
.fetch();
자세히는 따로 강의 듣고 ㄱㄱ 결국 JPQL이 기본이다.
select m from Member as m where m.age > 18
설계 토대로 예시들거임
select_문 :: =
select_절
from_절
[where_절]
[groupby_절]
[having_절]
[orderby_절]
update_문 :: = update_절 [where_절]
delete_문 :: = delete_절 [where_절]
TypedQuery<Member> query =
em.createQuery("SELECT m FROM Member m", Member.class);
Query query =
em.createQuery("SELECT m.username, m.age from Member m");
// 이름 기준
SELECT m FROM Member m where m.username=:username
query.setParameter("username", usernameParam);
// 위치 기준
SELECT m FROM Member m where m.username=?1
query.setParameter(1, usernameParam);
JPQL에서는 2가지 기준으로 매개변수를 지원하는데,
위치 기준으로 받을 시 중간에 값 하나만 끼워 넣어도 다 뒤틀리니까 이름 기준으로만 받는다.
JPQL문 안에 들어간 엔티티는 모두 영속성 컨텍스트에서 관리된다.
SELECT m FROM Member m -> 엔티티 프로젝션
SELECT m.team FROM Member m -> 엔티티 프로젝션 // 이렇게 하지마라! 조인되는게 예측이 안된다.
SELECT t FROM Member m join m.team t -> 엔티티 프로젝션 // 이렇게 하라
SELECT m.address FROM Member m -> 임베디드 타입 프로젝션(임베디드만으로는 안되고 엔티티소속으로 해야함)
SELECT m.username, m.age FROM Member m -> 스칼라 타입 프로젝션
SELECT m.username, m.age FROM Member m
// 패키지 명을 포함한 전체 클래스 명 입력 해야함
// 순서와 타입이 일치하는 생성자 필요하다.
List<MemberDTO> result = em.createQuery("select new 패키지명.MemberDTO(m.username, m.age)",MemberDTO)
SELECT
M.ID AS ID,
M.AGE AS AGE,
M.TEAM_ID AS TEAM_ID,
M.NAME AS NAME
FROM
MEMBER M
ORDER BY
M.NAME DESC LIMIT ?, ?
SELECT * FROM
( SELECT ROW_.*, ROWNUM ROWNUM_
FROM
( SELECT
M.ID AS ID,
M.AGE AS AGE,
M.TEAM_ID AS TEAM_ID,
M.NAME AS NAME
FROM MEMBER M
ORDER BY M.NAME
) ROW_
WHERE ROWNUM <= ?
)
WHERE ROWNUM_ > ?
//페이징 쿼리
String jpql = "select m from Member m order by m.name desc";
List<Member> resultList = em.createQuery(jpql, Member.class)
.setFirstResult(10)
.setMaxResults(20)
.getResultList();
SELECT m, t FROM Member m LEFT JOIN m.team t on t.name = 'A'
SELECT m.*, t.* FROM Member m LEFT JOIN Team t ON m.TEAM_ID=t.id and t.name='A'
SELECT m, t FROM Member m LEFT JOIN Team t on m.username = t.name
SELECT m.*, t.* FROM Member m LEFT JOIN Team t ON m.username = t.name
select m from Member m
where m.age > (select avg(m2.age) from Member m2)
select m from Member m
where (select count(o) from Order o where m = o.member) > 0
예제)
-- 팀A 소속인 회원
select m from Member m
where exists (select t from m.team t where t.name = ‘팀A')
-- 전체 상품 각각의 재고보다 주문량이 많은 주문들
select o from Order o
where o.orderAmount > ALL (select p.stockAmount from Product p)
-- 어떤 팀이든 팀에 소속된 회원
select m from Member m
where m.team = ANY (select t from Team t)
select i from Item i where type(i) = book
select
case when m.age <= 10 then '학생요금'
when m.age >= 60 then '경로요금'
else '일반요금'
end
from Member m
select
case t.name
when '팀A' then '인센티브110%'
when '팀B' then '인센티브120%'
else '인센티브105%'
end
from Team t
사용자 이름이 없으면 이름 없는 회원을 반환
select coalesce(m.username,'이름 없는 회원') from Member m
사용자 이름이 ‘관리자’면 null을 반환하고 나머지는 본인의 이름을 반환
select NULLIF(m.username, '관리자') from Member m
select function('group_concat', i.name) from Item i