본문 바로가기
  • 개발공부 및 일상적인 내용을 작성하는 블로그 입니다.
JPA

JPQL - JPQL 기본(1)

by 방구석 대학생 2020. 11. 15.

"인프런 - 자바 ORM 표준 JPA 프로그래밍 강의를 듣고 작성한 글 입니다."

www.inflearn.com/course/ORM-JPA-Basic#

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다. 초급 웹 개발 프로그

www.inflearn.com

 

 

JPQL(Java Persistence Query Language)

- JPQL 은 객체지향 쿼리 언어이다, 따라서 테이블을 대상으로 쿼리를 하는 것이 아닌 Entity 객체를 대상으로 쿼리 한다.

- JPQL 은 SQL 을 추상화해서 특정 데이터베이스 SQL 에 의존하지 않는다.

- JPQL 은 결국 SQL 로 변환된다.

 

* JPQL 의 기본 문법은 일반 SQL 문과 거의 똑같다.

 

JPA 에서 값을 바꿀때는 update 같은 것 없이 값만 변경되면, 트랜잭션 커밋 시점에 지동으로 update query 가 DB 에 전달된다.

그런데 이건 한건, 한건 씩 변경 사항을 적용할 때의 얘기이다.

그렇다면 한번에 여러가지의 데이터를 변경해야 하는 경우는 어떨까?

 

* 벌크 연산 : 한번에 여러가지의 데이터를 함께 처리하는 기능

update_문 :: update_절 [where_절]

delete_문 :: delete_절 [where_절]

-> JPA 에서 따로 관리하는 기능으로 추후에 다루게 될 때 자세하게 알아보자.

 

 

JPQL 문법

JPQL 문법 예시 : select m from Member as m where m.age > 18

- Entity 와 속성은 대,소문자를 구분한다.(Member, age) -> 자바 클래스에서 대,소문자를 구분하듯이 JPQL 에서도 객체에 대한 대,소문자를 구분한다.

- JPQL 키워드는 대,소문자를 구분하지 않는다.(SELECT FROM, where)

- 테이블 이름이 아닌, Entity 이름을 사용하며(Member) 별칭은 필수이다.(m, as 는 생략 가능)

 

* 집합과 정렬

기존 SQL 과 같이 select COUNT(), SUM(), AVG() 와 같은 집합이나 정렬 기능이 다 제공된다.

-> GROUP BY, HAVING, ORDER BY 또한 마찬가지로 똑같이 사용하면 된다.

 

 

TypedQuery, Query

- TypedQuery : 반환 타입이 명확할 때 사용한다.

- Query : 반환 타입이 명확하지 않을 때 사용한다.

- JpaMain.java

// 타입 정보를 명기할 수 있는 경우
TypedQuery<Member> query1 = em.createQuery("select m from Member m", Member.class);
TypedQuery<String> query2 = em.createQuery("select m.username from Member m", String.class);

// 타입 정보를 명기할 수 없는 경우
Query query3 = em.createQuery("select m.username, m.age from Member m");
// 찾아오는 데이터의 타입이 복수 일 경우 Member.class 와 같이 타입을 명기할 수가 없게된다.

 

* 결과 조회

- 결과가 하나 이상일 때, 즉 반환값이 컬렉션 타입일 경우 리스트를 반환한다. 결과가 없으면 빈 리스트를 반환한다.(즉, NullPointerException 에 대한 걱정을 하지 않아도 된다.)

-> query.getResultList();

- 결과가 정확히 하나 일 경우 단일 객체를 반환한다.(진짜 결과가 하나만 나올때만 써야 한다, 조심해야 함)

-> query.getSingleResult();

-> 단일 객체를 반환할 때 결과가 없을 경우 발생하는 익셉션 : NoResultException

-> 단일 객체를 반환할 때 결과가 둘 이상일 경우 발생하는 익셉션 : NonUniqueResultException

- JpaMain.java

List<Member> resultList = query1.getResultList(); // 결과가 하나 이상일 경우 List 타입으로 반환
Member result = query1.getSingleResult();
// 결과가 하나 일 경우 사용하는 메소드(식별자를 잘 활용해야 한다.)

 

* 그런데 결과가 둘 이상일 경우엔 익셉션이 터지는 걸 당연하게 볼 수 있으나, 결과가 없을 경우에 익셉션이 터지는 것에 대해서는 논란이 있다고 한다.(괜히 try - catch 문을 사용해야 하므로....)

 

그래서 나중에 Spring Data JPA 를 사용하게 되면 하나만 가져오는 함수들을 추상화 시켜서 제공을 해주는데, 이 경우 결과가 없으면 그냥 null 을 반환하거나 optional 을 반환한다.

즉, 익셉션을 터트리지 않는다.

그런데 이것도 결국 Spring 에서 코드 내부 구조를 살펴보면 try - catch 문을 사용하고 있는 것을 볼 수 있다.

(Spring Data JPA 쓸 때랑 헷갈리지 말자!)

 

 

파라미터 바인딩(Parameter Binding)

이름, 위치를 기준으로 파라미터를 바인딩 해줄 수 있다.

- JpaMain.java

Member member = new Member();
member.setUsername("member1");
member.setAge(10);
em.persist(member);

TypedQuery<Member> query4 = em.createQuery("select m from Member m where m.username = :username", Member.class);
query4.setParameter("username", "member1"); // where 절 parameter binding
Member singleResult = query4.getSingleResult();
System.out.println("singleResult = " + singleResult.getUsername());

- Hibernate SQL

Hibernate: 
    /* select
        m 
    from
        Member m 
    where
        m.username = :username */ 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_ 
        where
            member0_.username=?
singleResult = member1

 

위의 코드를 파라미터 체인을 활용하여 작성하면 다음과 같이 할 수 있다.

- JpaMain.java

Member param_result = em.createQuery("select m from Member m where m.username = :username", Member.class)
						.setParameter("username", "member1")
						.getSingleResult();
System.out.println("param_result = " + param_result.getUsername());

- Hibernate SQL

Hibernate: 
    /* select
        m 
    from
        Member m 
    where
        m.username = :username */ 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_ 
        where
            member0_.username=?
param_result = member1

 

파라미터 바인딩을 할 때 주의할 점?

- 위치 기준 바인딩은 왠만하면 쓰지 말자.

: 1,2,3 순서상에서 중간에 다른 데이터를 하나 더 끼워넣으면 순서가 밀려버려서 장애가 발생하게 될 수도 있다.

반면에 이름 기준 바인딩을 활용하면 위치가 바뀐다고 해도 그로인한 장애가 발생하지 않게 된다.

 

 

 

다음 글에서는 JPQL 에서의 프로젝션, 페이징과 같은 다른 기능들 또한 알아보자.

'JPA' 카테고리의 다른 글

JPQL - JPQL 기본(3)  (0) 2020.11.16
JPQL - JPQL 기본(2)  (0) 2020.11.15
JPQL - JPQL 소개(2)  (0) 2020.11.13
JPQL - JPQL 소개(1)  (0) 2020.11.13
실전 예제 6 - 값 타입  (0) 2020.10.22