Java/ORM

JAVA ORM - JPA(JPQL)

티코딩 2024. 8. 8. 14:26

JPQL(Java Persistencce Query Language)

JPA에서 제공하는 쿼리언어.SQL과 유사하지만, 테이블이 아닌 엔티티 객체를 대상으로 쿼리를 작성한다.

@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private int age;
	...
}

 

이 멤버라는 엔티티에 대해 쿼리를 작성한다 치자.

EntityManager em = entityManagerFactory.createEntityManager();
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m", Member.class);
List<Member> members = query.getResultList();

main문에 이런식으로 쿼리를 작성할 수 있다.

하지만, 쿼리의 조건이 바뀌거나 할때 동적쿼리를 작성해야하는데 이 때 사용되는게 Criteria API 이다.

Criteria API 를 사용하기위해

CriteriaBuilder cb = em.getCriteriaBuilder();

CriteriaBuilder객체를 먼저 생성해준다.

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 resulstList = em.createQuery(cq).getResultList();

그다음 쿼리를 작성해주고 경과를 넣어준다.

이런방식으로 쿼리를 짠다면, 동적쿼리를 짜기에 좋다. 

하지만 크리테리아는 sql같지도않고 너무 어렵다.

대체제로 QueryDSL을 사용한다.

 

QueryDSL

크리테리아 대체제로 동적쿼리 작성에 이점이 있고, 자바코드로 JPQL을 작성할 수 있고, 컴파일시점에 오류를 잡을 수 있다는 장점이 있다.

JPAQueryFactory queryFactory = new JPAQueryFactory(em);
        QMember qMember = QMember.member;

        String nameParam = "John";
        Integer ageParam = 25;

        List<Member> members = queryFactory.selectFrom(qMember)
                                           .where(nameEq(nameParam), ageGt(ageParam))
                                           .fetch();

확실히 크리테리아 보다 훨씬 가독성도 좋고 사용하기에도 편한게 보인다.

이걸 알기전에는 꼭 JPQL을 알고하면 좋다.

 

Native SQL

em.createNatvieQuery(쿼리문).getResultList(); 하면 쿼리문 자리에 생 쿼리를 넣어도 잘 작동한다.

 

문법

엔티티와 속성은 대소문자구분O, 키워드는 구분X, 엔티티이름 사용함. 테이블이름X, 별칭은 필수

TypeQuery : 반환 타입이 명확할 때.

Query : 반환타입이 불분명할 때.

TypedQuery<Member> query1 = em.createQuery("select m from Member m", Member.class);
Query query2 = em.createQuery("select m.username, m.age from Member m");

결과조회

query.getResultList(): 결과가 여러개일 때.

query.getSingleResult(): 결과가 하나일 때.

TypedQuery<Member> query1 = em.createQuery("select m from Member m", Member.class);
List<Member> resultList = query.getResultList(); // 결과없으면 빈 리스트반환

TypedQuery<Member> query1 = em.createQuery("select m from Member m where m.id = 1", Member.class);
Member result = query.getSingleResult(); // 결과없으면예외, 두개이상이면 예외.

페이징

setFirstResult(int startPosition) : 조회 시작위치

setMaxResulst(int maxResult) : 조회할 데이터수

List<Member > result = em.createQuery("select m from Member m order by m.age desc", Member.class)
	.setFirstResult(10)
	.setMaxResults(20)
	.getResultList();

 

서브쿼리는

WHERE, HAVING, SELECT절에서만 사용 가능. FROM절의 서브쿼리는 불가능