JPA/JPA 기본

38. JPQL 기본 문법

sdafdq 2023. 10. 30. 09:30

Java Persistence Query Language

 

JPQL은 객체지향 쿼리 언어

테이블 대상이 아니라 자바 내의 엔티티 객체 대상.

 

JPQL은 SQL을 추상화 한 것이라 특정DB에 의존하지 않음.

 

JPQL은 결국 SQL로 변환됨.

예제

 

JPQL 해볼 예제임.

코드

@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;

    private String username;
    private int age;


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

 

@Entity
public class Team {
    @Id @GeneratedValue
    private Long id;

    private String name;

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

팀과 상호 연관관계. Many쪽인 Member가 주인.

 

@Entity
@Table(name = "orders")
public class Order {
    @Id @GeneratedValue
    private Long id;

    private int orderAmount;

    @Embedded
    Address address;

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

Embedded 타입 사용.

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

 

Hibernate: 
    create table orders (
        orderAmount integer not null,
        id bigint not null,
        product_id bigint,
        city varchar(255),
        street varchar(255),
        zipcode varchar(255),
        primary key (id)
    )

제대로 잘 들어 감.

 

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

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

order와 product는 단방향 연관관계.

order가 다 쪽.

 

 

여튼 환경은 이렇고, 본격적으로 JPQL 문법.

sql이랑 거의 똑같다.

join 등 약간 다른 부분이 있긴 하다.

 

벌크 연산 이란 것이 있다.

한번에 회사원들 연봉 10% 인상한다던지 한번에 여러 개 연산.

나중에 배움

 

문법

select m from Member as m where m.age > 18

거의 비슷한데, 약간 다른 건 저 Member가 테이블이 아닌 객체

엔티티와 속성은 대소문자 구분한다. 객체랑 필드 대소문자 구분 하듯이.

select from where같은 키워드는 대소문자 구분X

별칭은 필수이다. as 생략가능.

 

sql 함수

다 제공 됨.

 

group by, having

order by 똑같이 쓰면 됨.

 

반환타입 명확할 때 : TypedQuery

명확하지 않을 때 : Query

 

TypedQuery<Member> tyQuery = em.createQuery("select m from Member m", Member.class);

Query query = em.createQuery("select m.username, m.age from Member m");

이런 거.

위는 반환타입이 명확하니 TypedQuery

아래에는 명확하지 않음.

예를 들어 m.username만 가지고 오면 String으로 명확하게 할 수 있었는데.

 

 

 

결과조회

결과가 하나 이상일때

TypedQuery<Member> tyQuery = em.createQuery("select m from Member m", Member.class);
List<Member> members = tyQuery.getResultList();

query.getResultList()

 

TypedQuery<Member> tyQuery = em.createQuery("select m from Member m where m.id = "+ id, Member.class);
Member member = tyQuery.getSingleResult();

하나만 가져올 때.

 

query.getSingleResult();

 

 

근데 좀 주의할 게 있음

getResultList() :  결과가 하나이상일 때 쓰는 것이고, 결과 없으면 빈 리스트 반환

 

getSingleResult() : 결과가 정확히 하나여야 함.

없으면 javax.persistence.NoResultException

결과가 둘 이상이면 javax.persistence.NonUniqueResultException 던짐

 

 

 

파라미터 바인딩

TypedQuery<Member> tyQuery = em.createQuery("select m from Member m where m.id = :id", Member.class);
tyQuery.setParameter("id", 3);
Member member = tyQuery.getSingleResult();

이런 식으로.

:id 해서 이름바인딩

query.setParameter("이름", 값);

 

참고로,

Member memeber = em.createQuery("select m from Member m where m.id = :id", Member.class)
                .setParameter("id",3)
                .getSingleResult();

이렇게 쓰라고 만든거임. 저렇게 안나눠도 됨.

그리고, 바인딩 할 때 이름기준 말고 위치기준도 있긴 한데, (:이름 대신 ?1 하면서 순서 넣는거)

그냥 이름 쓰셈. 그게 더 명확함.

 

 

'JPA > JPA 기본' 카테고리의 다른 글

40. 페이징  (0) 2023.10.31
39. 프로젝션(select)  (0) 2023.10.30
37. JPQL  (0) 2023.10.30
36. 값타입 실전  (0) 2023.10.30
35. 값타입 컬렉션  (0) 2023.10.29