오봉이와 함께하는 개발 블로그

JPA - 기본 문법과 쿼리 API 본문

BE/JPA

JPA - 기본 문법과 쿼리 API

오봉봉이 2022. 6. 30. 00:05
728x90

JPQL(Java Persistence Query Language)

  • JPQL은 객체지향 쿼리 언어다. 따라서 테이블 대상이 아닌, 엔티티 객체 대상으로 쿼리한다.
  • JPQL은 SQL을 추상화해서 특정 DB SQL에 의존하지 않는다.
  • JPQL은 결국 SQL로 변환된다.

모델

모델 기반 코드 작성

@Entity
@Getter @Setter
public class Member {
    @Id
    @GeneratedValue
    private Long id;
    private String username;
    private int age;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;
}

@Entity
@Getter @Setter
public class Team {
    @Id @GeneratedValue
    private Long id;
    private String name;

    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<>();
}

@Entity
@Table(name = "ORDERS") // order는 예약어라 테이블명 변경 필요
@Getter @Setter
public class Order {
    @Id @GeneratedValue
    private Long id;
    private int orderAmount;

    @Embedded
    private Address address;

    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;
}

@Embeddable
@Getter @Setter
public class Address {
    private String city;
    private String street;
    private String zipcode;
}

@Entity
@Getter @Setter
public class Product {
    @Id @GeneratedValue
    private Long id;

    private String name;
    private int price;
    private int stockAmount;

}

JPQL 문법

SQL 문법과 똑같다.
(사진)

아래 update문과 delete문은 한 번에 여러 값을 업데이트 할 때 사용하는 벌크연산이라는 개념을 다룰 때 설명할 수 있겠다.

  • select m from Member(엔티티) as m where m.age > 18
    • 엔티티와 속성은 대소문자를 구분한다(Member, age)
    • JPQL 키워드는 대소문자를 구분하지 않는다(SELECT, from, where)
    • 테이블의 이름이 아닌, 엔티티의 이름을 사용한다.(Member)
    • 별칭(m)은 필수다.(as는 생략 가능)

집합과 정렬

select
  COUNT(m), -- 회원수
  SUM(m.age), -- 나이 합
  AVG(m.age), -- 평균 나이 
  MAX(m.age), -- 최대 나이 
  MIN(m.age) -- 최소 나이
from Member m
  • GROUP BY, HAVING, ORDER BY 모두 동일하게 사용 가능

TypeQuery, Query

  • TypeQuery : 반환 타입이 명확할 때 사용
  • Query : 반환 타입이 명확하지 않을 때 사용
// em.createQuery("SELECT m.username, m.age from Member m", 타입.class);

TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m", Member.class);

// m.username은 String, m.age는 int기 때문에 타입을 명시할 수 없다.
Query query = em.createQuery("SELECT m.username, m.age from Member m"); // Member.class가 없음.

결과 조회 API

  • getResultList() : 결과가 하나 이상일 때, 리스트 반환
    • 결과가 없으면 빈 리스트 반환
  • getSingleResult() : 결과가 정확히 하나, 단일 객체 반환
    • 결과가 없으면 : javax.persistence.NoResultException
    • 둘 이상이면 : javax.persistence.NonUniqueResultException

파라미터 바인딩 - 이름 기준, 위치 기준

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);

중간에 다른 파라미터를 삽입하면 순서가 다 꼬이기 때문에 위치 기준은 가급적 사용하지 않을 것을 권장한다.

// 이름 기준
TypedQuery<Member> query = em.createQuery("select m from Member m where m.username = :username", Member.class);
query.setParameter("username", "test"); // 여기서 파라미터 설정
Member findMember = query.getSingleResult();

// 체인 방식으로 엮어서 개선
Member result = em.createQuery("select m from Member m where m.username = :username", Member.class)
        .setParameter("username", "test")
        .getSingleResult();

// 위치 기준
TypedQuery<Member> query = em.createQuery("select m from Member m where m.username = ?1", Member.class);
query.setParameter(1, "test"); // 여기서 파라미터 설정
Member findMember = query.getSingleResult();

// 체인 방식으로 엮어서 개선
Member result2 = em.createQuery("select m from Member m where m.username = ?1", Member.class)
        .setParameter(1, "test")
        .getSingleResult();
출처 : 인프런 김영한 지식공유자님의 스프링 부트와 JPA 실무 완전 정복 로드맵 강의
728x90

'BE > JPA' 카테고리의 다른 글

JPA - 페이징  (0) 2022.06.30
JPA - 프로젝션(select)  (0) 2022.06.30
JPA - 객체 지향 쿼리 언어 소개  (0) 2022.06.29
JPA - 실전 예제 6 - 값 타입 매핑  (0) 2022.06.29
JPA - 값 타입 컬렉션  (0) 2022.06.29
Comments