[JPA] - 나머지 쿼리

2023. 1. 4. 16:24·Spring/JPA
728x90
반응형

1. 다형성 쿼리 

> treat, item 등의 쿼리문 사용 가능

> ex) select i from Item i where treat(i as Book).author= 'kim'; // treat = 일종의 캐스팅

> 사용한 테이블 전략에 맞춤형으로 SQL이 나가게 됨. 

 

 

2. 엔티티 직접 사용

> 엔티티 칼럼을 직접 사용하면, SQL에서는 당연히 해당 엔티티의 기본 키값을 사용

> 그냥 엔티티를 직접 파라미터로 전달해서 사용할 수 있다는 특징이 있음

 

가령, 

 

em.createQuery("select m from Member m where m = :member").setParameter("member", member)
em.createQuery("select m from Member m where m.id = :memberId").setParameter("memberId", memberId)

 

 두 JPQL 모두 실 SQL 결과는 "select m from Member m where m.id = {}"

 

team 이 teamA 인 녀석의 멤버들을 모두 가져와라

JPQL : select m from Member m where m.team = :teamA or m.teamId = :teamAId

 

 

3.Named Query

> 미리 정의해서 이름을 부여해두고 사용하는 JPQL (Entity 따위 맨 위에 Annotation 으로 Query 를 미리 짜놓고, 그 쿼리에 대한 key 이름을 만들어 놓는다)

> 장점 1 : 앱 로딩시 초기화를 해놓고, 앞으로 동일한 쿼리에 대해서는 재사용을 한다 

> 장점 2: 앱 로딩 시점에 쿼리를 검증해준다

>>>>>>>>>>>>>>> 2가 매우 막강함. 

 

@Entity
@NamedQuery(
    name = "Member.findByUsername",
    query = "select m from Member m where m.username = :username"
) // 관례상 사용할 Entity 에 많이 함
public class Member {
    ...
}

void test(){
    tx.begin()
    try{
    ...
    
    List<Member> members = em.createNamedQuery("Member.findByUsername", Member.class)
        .setParameter("username", "김삿갓")
        .getResultList();
    
    ...
    }catch{
    ...
    }
}

에러 중 제일 좋은 오류 :: 컴파일 시점에 나는 오류. 빨리 잡을 수 있음. 

에러 중 제일 나쁜 오류 :: 유저가 발견하는 오류. 

>> SQL이 잘못되었음을 실행 시점에 알 수 있기 때문에, 네임드 쿼리는 실수할 확률이 줄어든다. 

>> SPring Data JPA 를 써도, @Query 를 통해서 등록해놓을 수 있음. 이것도 네임드 쿼리와 동일

>> 실무에서는 바로 위에서 말한 @Query 를 통해서 네임드 쿼리를 사용하긴 해도, 엔티티에 명명해서 하는건 조금 비추. 너무 지저분해지고, 여기 저기 쿼리가 있는 건 좋지 않음. 

 

 

4. 벌크 연산. 

 

가정 : 재고가 10개 미만인 모든 상품의 가격을 10% 상승시키려면?

현재 

1. 재고가 10개 미만인 상품 모~두 조회 (백만개)

2. 각 상품의 가격을 모~두 10% 상숭 (백만개)

3. 커밋 시점에 변경 감지 작동, SQL 나감.  (백만개) 

 

** 벌크 연산이란, 쿼리 한번으로 여러 테이블의 로우를 변경할 수 있는 것이다. 

 

모든 회원의 나이를 20살로 바꾸자

JPQL : update Membe m set m.age = 20 후 . executeUpdate() 를 수행

em.createQuery({JPQL}).executeUpdate() 는 영향 받은 항목 수를 반환한다. 

 

* 주의 사항 :: 벌크 연산은 영컨을 무시하고 바로 DB에 직접 쿼리를 날린다. 따라서 영컨을 사용하다가 벌크를 하면 DB가 좀 꼬일 수 있음. 

 

두가지 해결책

>>>> 1) 벌크 연산을 먼저 실행

>>>> 2) 벌크 연산 수행 후 영컨 초기화

 

1 설명 )) 영컨을 하다가 벌크가 문제가 되는거지, 벌크 후에 영컨을 하는건 문제가 안되니까 저렇게 하면 ㄱㅊ

2 설명 )) 

회원 조회. 연봉 5천만. 벌크 연산으로 6천만으로 상승. 1차 캐시에는 아직 5천만 >>> 문제 발발 (항상 이놈의 1차캐시가 문제임)

따라서 6천만으로 상승시킨 뒤에 Flush 를 해주고 (플러쉬는 차피 벌킹하며 SQL 나가면 자동으로 됨, 플러쉬가 되는 상황 3가지 기억!!), 영컨을 초기화하면, 인앱에서 다시 가져올 때는 쿼리를 날려야 하고, 6천만이 되어있을 것. 

 

void test(){
    tx.begin();
    try{
        ...
        Team teamA = new Team();
        teamA.setName("teamA");
        em.persist(teamA);
        
        ... 
        //member 1,2,3 를 만들고 teamA 지정하고 영속화한 상태
        ...
        
        int result = em.createQuery("update Member m set m.age = 20") // 20살로 모두 변경
                       .executeUpdate();
                       
        // 이미 FLUSH 됨, 영컨은 가만히 있음
        
        System.out.println("resultCnt = " + resultCnt);
        
        System.out.println("member1.getAge() = " + member1.getAge());
        System.out.println("member2.getAge() = " + member2.getAge());
        System.out.println("member3.getAge() = " + member3.getAge());
        
        tx.commit();
    }catch{
    ...
    }
}

 

나이를 출력해보면 출력값들이 모두 20살이 안나오고 초기에 Setting 한 나이들이 조회되는 것을 알 수 있다. 이 상태로 인 앱에서 로직을 수행하는 것임. (트랜젝션 내) >> 플러쉬는 되었겠지만, 영컨 초기화가 안되어 있기 때문에 1차캐시에 값들이 그대로 있다.  (데이터 정합성 문제) 

 

clear 후에 다시 조회해야함. 

 

...
int resultCount = em.createQuery("update Member m set m.age = 20")
                     .executeUpdate();

em.clear(); // *************** 중요

Member findMember = em.find(Member.class, member1.getId());
System.out.println("member1.getAge() = " + member1.getAge());

 

이렇게 하면 데이터 정합성이 맞음. 이게 위 2번에 대한 설명임. 

 

암튼 벌크 연산시에는 영컨을 어떻게 사용하고 있는지 Repo 와 잘 생각하며 파악해야 한다. 안그러면 ㄹㅇ ㅈ되는거임.

 

 

728x90
반응형

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

[JPA] 양방향 매핑 관계 로딩 방법 별로 살펴보기 (N+1 문제는 도대체 언제?)  (0) 2024.03.01
[JPA] 연관 객체 불러오기.. Fetch Join 정말 괜찮을까?  (0) 2023.12.03
[JPA] JPQL 쿼리 2 (FETCH JOIN의 등장)  (0) 2023.01.03
[JPA] JPQL 쿼리  (0) 2022.12.29
[JPA] - 값 타입  (0) 2022.12.29
'Spring/JPA' 카테고리의 다른 글
  • [JPA] 양방향 매핑 관계 로딩 방법 별로 살펴보기 (N+1 문제는 도대체 언제?)
  • [JPA] 연관 객체 불러오기.. Fetch Join 정말 괜찮을까?
  • [JPA] JPQL 쿼리 2 (FETCH JOIN의 등장)
  • [JPA] JPQL 쿼리
문케이크
문케이크
    반응형
  • 문케이크
    누구나 개발할 수 있다
    문케이크
  • 전체
    오늘
    어제
    • 전체 보기 (122)
      • CS 이론 (13)
        • 운영체제 (8)
        • 네트워크 (2)
        • 알고리즘 (0)
        • Storage (3)
      • Spring (26)
        • Spring 기본 (12)
        • Spring 심화 (0)
        • JPA (11)
        • Spring Security (3)
      • 리액티브 (0)
        • RxJava (0)
      • SW 설계 (14)
        • OOP (0)
        • UML (3)
        • OOAD (0)
        • Design Pattern (11)
      • Java (8)
      • 웹 운영 (17)
        • AWS (15)
        • 운영 구축 (2)
      • Testing (3)
        • Unit (3)
      • Extra (3)
        • API 적용 (1)
      • 인프라 기술 (5)
        • Kubernetes (2)
        • Elasticsearch (3)
      • Logging (7)
        • Spring (5)
        • 인프라 (2)
      • 일상 (2)
        • 음식점 리뷰 (2)
        • Extra (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • 문케이크의 블로그
  • 인기 글

  • 태그

    OOP
    Configuration
    analyzer
    n+1
    김영한
    Java
    디자인 패턴
    GoF
    단위테스트
    Composite
    k8s
    composition
    spring boot
    junit
    Design Pattern
    decorator
    lazy loading
    di
    객체지향
    mockito
    BEAN
    spring container
    Setter
    runtime exception
    JPA
    lombok
    elasticsearch
    Spring
    SRP
    OOAD
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
문케이크
[JPA] - 나머지 쿼리
상단으로

티스토리툴바