Zayson
A to Zayson!
Zayson
전체 방문자
오늘
어제
  • 분류 전체보기 (132)
    • Computer Science (20)
      • Network (4)
      • DB (12)
      • OS (4)
    • Algorithm (32)
      • 완전탐색(Brute-Force) (3)
      • 그리디(Greedy) (6)
      • 투포인터(Two-Pointer) (1)
      • 그래프(Graph) (5)
      • BFS & DFS (9)
      • 구현, 시뮬레이션(Implementation) (5)
      • 다이나믹 프로그래밍(DP) (3)
    • Backend (51)
      • Spring Boot (19)
      • JPA (16)
      • Kafka (2)
      • Java (13)
      • Kotlin (1)
    • DevOps (1)
      • Jenkins (5)
      • Oracle Cloud Infrastructure (1)
      • Kubernetes & Docker (1)
    • Trouble Shooting (3)
      • JPA (1)
      • Spring Boot (2)
    • 회고 (5)
      • 엔빵 프로젝트 포스트 로드맵 (1)
      • 2022년 (4)
    • Kafka (7)
      • Kafka (5)
      • Kafka Connect (2)
    • 기술 서적 (6)
      • 데이터 중심 애플리케이션 설계 (3)
      • 개발자가 반드시 정복해야할 객체 지향과 디자인 패턴 (2)
      • 가상 면접 사례로 배우는 대규모 시스템 설계 기초 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

태그

  • 프로그래머스
  • 엔빵프로젝트
  • 나 혼자 스프링부트!
  • JPA
  • 그리디
  • kafka
  • Backend
  • 구현
  • 관계형 데이터베이스 실전 입문
  • Java
  • 완전탐색
  • CS
  • spring boot
  • Kafka Connect
  • 라이브스터디
  • 백준
  • dfs
  • BFS
  • SpringBoot
  • Computer science

최근 글

티스토리

hELLO · Designed By 정상우.
Zayson

A to Zayson!

JPQL 중급
Backend/JPA

JPQL 중급

2022. 8. 3. 12:18

경로 표현식

  • .을 찍어 객체 그래프를 탐색하는 것이다.
  • 연관 필드 : 연관관계를 위한 필드
    • 단일 값 연관 필드 : @XtoOne 대상이 엔티티이다.
    • 컬렉션 값 연관 필드 : @XToMany 대상이 컬렉션이다.
  • 상태 필드는 단순히 값을 저장하는 필드이며, 엔티티가 아니기 때문에 더 이상 탐색이 불가능하고 탐색의 종점이다.
class Member {
    private String username; 

    @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "TEAM_ID")
  private Team team;

    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();
}

// jpql
m.username -> 상태 필드
m.team     -> 단일 값 연관 필드
m.orders   -> 컬렉션 값 연관 필드

 

  • 단일 값 연관 경로는 A 엔티티 → B 엔티티로 탐색이 이동되고, 묵시적으로 내부 조인(Inner Join)이 발생한다. B 엔티티에 .을 찍어 계속해서 탐색이 가능하다.
  • 컬렉션 값 연관경로는 묵시적인 내부 조인이 발생하지만 탐색을 더 이상 할 수없다. (size 조회는 가능하다.)
  • 컬렉션 값을 탐색하는 경우에는 from절에 명시적으로 조인을 걸어 별칭을 얻어서 조회한다.
select m from Team t join t.members m

 

  • 🔥 묵시적 조인을 지원하지만 반드시 명시적으로 조인절을 사용하자!!!
  • JOIN 키워드를 직접적으로 사용하자.
select m from Member m join m.team t
select m.team from Member m

 

다형성 쿼리

  • 상속 구조인 경우에 type, treat 문법을 사용할 수 있다.
  • type이 DiscriminatorColumn(DTYPE) 으로 바뀌어서 사용된다.
[JPQL] select i from Item i where type(i) IN (Book, Movie)
[SQL]  select i.* from Item i where i.DTYPE in ('B','M')

 

  • treat은 캐스팅과 유사하다.
  • 상속 구조에서 부모타입을 특정 자식 타입으로 다룰 때 사용한다.
// treat을 이용해 다운 캐스팅 효과를 낸다. auther는 Book의 필드
[JPQL] select i from Item i where tret(i as Book).auther = 'kim'
[SQL]  select i.* from Item i where i.DTYPE = 'B' and i.auther = 'kim'

 

엔티티 직접 사용

  • JPQL에서 엔티티를 직접 사용하는 경우 SQL에서는 해당 엔티티의 기본 키값으로 매핑되어 사용된다.
  • JPQL에서 엔티티를 setParameter를 통해서 넘겨도 SQL에서는 기본 키 값으로 매핑된다.
[JPQL] select count(m) from Member m. // 엔티티를 넘긴 경우
[JPQL] select count(m.id) from Member m // 식별자를 넘긴 경우 

[SQL]  select count(m.id) from Member m

String query = "select m from Member m where m = :member";
List<Member> findMember = em.createQuery(query, Member.class)
                .setParameter("member", member).getResultList();

 

  • 연관관계의 엔티티를 직접 사용하는 경우 SQL에서는 해당 엔티티의 외래 키 값으로 매핑되어 사용된다.
String query = "select m from Member m where m.team = :team";

// teamA의 식별자로 매핑된다.
List<Member> findMember = em.createQuery(query, Member.class)
                    .setParameter("team", teamA).getResultList();

 

Named 쿼리

  • 엔티티에 쿼리를 직접 정의하고 이름을 부여해서 사용하는 JPQL이다. (정적 쿼리만 가능하다.)
  • @NamedQuery, XML에 정의해서 사용한다.
  • 정적 쿼리(변하지 않음)이기 때문에 애플리케이션 로딩 시점에 초기화하고 쿼리를 검증하고 캐싱한다!!
  • NamedQuery안에 문자열로 쿼리를 지정해서 실행은 되지만, 애플리케이션 실행 시에 에러를 발생시킨다!
@Entity
@NamedQuery(
        // 관례 : 엔티티명.이름
        name = "Member.findByUsername",
        query = "select m from Member m where m.username = :username"
)
public class Member { ... }

List<Member> findMember = em.createNamedQuery("Member.findByUsername", Member.class)
                    .setParameter("username", "회원1")
                    .getResultList();

Spring Data JPA에서 @Query 애노테이션을 이용한다.

 

벌크 연산

  • SQL의 UPDATE, DELETE (PK를 이용한 한건 업데이트, 및 삭제 제외) 문을 벌크 연산이라 한다.
  • JPA의 변경 감지를 이용해 모든 데이터를 변경하거나 삭제하려 하면 쿼리가 많이 발생된다!
    • 데이터가 100만건이면 루프를 돌면서 100만 번 쿼리가 실행된다.
// 모든 회원 나이 변경하기 
int resultCount = em.createQuery("update Member m set m.age = 20").executeUpdate();

 

  • UPDATE, DELETE는 JPA의 표준 스펙에서 벌크연산을 지원한다.
  • Hibernate는 (Insert into … select)로 삽입하는 INSERT 연산도 지원한다.
  • 벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리를 날린다.
    1. 영속성 컨텍스트에 값을 넣지 않고 벌크 연산을 먼저 실행한다.
    2. 벌크 연산을 수행한 후 영속성 컨텍스트를 초기화한다. (영속성 컨텍스트에 값이 있을 수도 있는 경우)
Member member = new Member();
member.setUsername("회원1");
member.setTeam(teamA);
member.setAge(0);
em.persist(member); // Flush 발생 (영속성 컨텍스트에는 나이가 0인 상태 회원)

// 벌크 연산 (DB에 직접 데이터 *반*영)
int resultCount = em.createQuery("update Member m set m.age = 20")
                    .executeUpdate();

1) // 영속성 컨텍스트에 member가 있기 때문에 1차 캐시에서 조회한다 => age = 0 으로 출력
    Member findMember = em.find(Member.class, member.getId());
    System.out.println("findMember.getAge() = " + findMember.getAge()); 

2) // 영속성 컨텍스트를 초기화하면 DB에서 영속성 컨텍스트로 가져오기 때문에 age = 20
  em.clear();
    Member findMember = em.find(Member.class, member.getId());
    System.out.println("findMember.getAge() = " + findMember.getAge()); 

벌크 연산은벌크 연산은 Spring Data JPA에서 @Modifying를 이용한다.

 

📄 References

김영한 님의김영한 님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 : https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

반응형
저작자표시 비영리 변경금지 (새창열림)

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

Spring Data Jpa  (0) 2022.08.22
페치 조인 (Fetch Join)  (0) 2022.08.03
JPQL 기본  (0) 2022.07.29
값 타입  (0) 2022.07.26
영속성 전이 (Cascade), 고아 객체  (0) 2022.07.21
    'Backend/JPA' 카테고리의 다른 글
    • Spring Data Jpa
    • 페치 조인 (Fetch Join)
    • JPQL 기본
    • 값 타입
    Zayson
    Zayson
    공부한 내용을 정리하는 공간

    티스토리툴바