스프링 강의 요약-(6)

이진우·2023년 7월 1일
0

스프링 강의 요약

목록 보기
7/13

아래는 김영한 강사님의 스프링 JPA 표준 강의를 듣고 정리한 내용이다.

서브쿼리

select m from Member m where m.age>(select avg(m2.age) from Member m2)

이 경우 m2 를 새로 정의 해서 성능이 잘 나온다. 하지만

select m from Member m where (
select count(o) from Order o where m=o.member)>0

이 경우 m을 긁어오기에 성능 안나올수 있다.

서브쿼리 지원함수

  • EXISTS
  • 서브쿼리에 결과가 존재하면 참.
    All: 모두 만족시 참
    ANY,SOME:같은 의미
  • IN
  • 서브 쿼리의 결과 중 하나라도 같은 것이 있으면 참

    사용예

    select m from Member m where 
    exists (select t from m.team t where t.name='팀A')
    
    select o from Order o
    where o.orderAmount>ALL(select p.stockAmount from Product p)
    
    select m from Member m
    where m.team=ANY(select t from Team t)

    JPQL타입을 표현할때는

    문자는 ''사이에 숫자는 10L,10D,10F Boolean:TRUE,FALSE로

    사용예

    String query="select m.username,'hello', true FROM Member m";
    List<Object[]> result=...
    Object[0]:유저이름,Object[1]:Hello,Object[2]:true 들어간다

    ENUMTYPE사용예

    where m.type=jpql(클래스).MemberType(클래스명).Admin;

    상속관계에서 엔티티 타입 구분 시 예제

    "select i from Item i where type(i)=Book",Item.class)

    type이 book인 것만 추출한다

    조건식-CASE식

    예제

    select 
        case when m.age <= 10 them '학생요금'
             when m.age >= 60 then '경로요금'
             else '일반요금'
        end
    from Member m
  • COALESE:하나씩 조회해서 NULL이 아니면 반환
  • 예제

    select coalesce(m.username,'이름 없는 회원') from Member m

    username 없으면 이름 없는 회원으로 나온다.

  • NULLIF:두 값이 같으면 NULL반환, 다르면 첫번째 값
  • 예제

    select NULLIF(m.username,'관리자') from Member m

    JPQL함수

    기본함수와 사용자정의함수로 나누어져 있으며
    기본함수에는
    문자 두개 더하는 concat
    문자 자르는 SUBSTRING
    공백 제거하는 TRIM
    대소문자로 전환하는 LOWER,UPPER
    문자길이 찾는 LENGTH
    문자열에서 문자열 위치 찾는 LOCATE
    ABS,SQRT,MOD 같은 수학함수
    콜렉션에서 사이즈 계산할 수 있는 size함수
    등이 있다.
    사용자 정의함수는 교재 참고

    JPQL-경로표현식

    상태필드: 단순히 값 저장 위한 필드(ex.m.username)
    연관필드:1)단일값 연관 필드 2)컬렉션 값 연관 필드
    연관필드들은 묵시적 내부 조인이 발생할 수 있다.
    단일값 연관 경로는 select m.teamname 처럼 탐색이 가능하지만
    컬렉션 값 연관 경로는 묵시적 join으로는 탐색이 불가능 하니(t.members.size가 최선) 명시적 join 으로 해결가능

    참고

    컬렉션 값 연관 경로 가져올떄 List result로 받는다

    결론

    명시적 join쓰자

    페치조인

    페치조인의 필요성

    일단 기본적으로 type을 LAZY 로 하는 이유는 조회할때 한 방에 다른 엔티티까지 쿼리가 나가고 그거에 연관된 엔티티까지 쿼리가 나가면 비효율 적이다.

    그래서 LAZY 를 쓰는데 조회할때 다른 Entity 의 값도 가져오려면 LAZY 타입이니 쿼리가 많이 나가서 fetch JOIN 으로 한 쿼리로 연결 시킨다.

    그러면 EAGER 바꾸면 될 것같지만, EAGER 는 예측할 수 없는 문제도 있고, 다른곳에서 조회할때는 또 다른 엔티티의 값이 필요가 없을 수도 있기 때문에 기본은 LAZY로 해두고 다른 엔티티의 값이 필요한 특수한 경우에만 fetch JOIN 을 한다.


    즉 객체 그래프를 동적으로 명시적으로 가지고 오고 싶을 때 fetch join 을 쓴다

    N+1문제를 fetch join으로 해결가능하다

    1대 다 관계에서 fetch join

    데이터가 뻥튀기 될 수 있다.
    select t from Team t join fetch t.members 

    이러면 데이터베이스 테이블을 따라서 memberID랑 Name만 다른 것을 다른 컬럼으로 본다



    같은 식별자를 가진 Team 엔티티를 제거하려면 distinct를 써주면 된다

    페치조인VS일반조인

    일반 조인은 실행 시에 연관된 엔티티를 함께 퍼올리지 않는다

    페치조인 한계

    1)페치조인 대상 별칭 불가->fetch join 을 여러개 쓸때만 가능
    2)둘이상의 컬렉션 페치 조인 불가->다대다 데이터 뻥튀기
    3)컬렉션을 페치 조인시 페이징 API 사용 불가:DB에서 데이터를 다 끌고 와서 메모리에서 페이징 하기 때문에 장애나기 매우 좋다
    사용을 원한다면?
    @OneToMany위에 @Batchsize(size=100) 혹은 global setting 으로 배치 size를 이용해서 해결

    페치조인보다는 일반조인

    여러 테이블 조인해서 엔티티가 가진 모양이 아닌 다른 결과를 할때 일반 조인을 사용해서 필요한 데이터만 DTO로 반환하는 것이 효과적

    다형성 쿼리

    조회 대상을 특정 자식으로 한정할떄
    select i from Item i where type(i) IN (BOOk,Movie)//Item 중 Book,Movie를 조회해라

    상속 구조에서 부모 타입을 특정 자식 타입으로 다룰 떄

    select i from Item i where treat(i as Book).author='kim'

    엔티티를 직접 사용

    기본키값 외래 키값 모두 JPQL에서 엔티티를 직접 사용하면 SQL에서는 해당 엔티티의 기본 값을 사용

    Named 쿼리

    미리 정의해서 이름을 부여해두고 사용하는 JPQL인데
    정적 쿼리만 가능하기 떄문에
    장점 1) 문법 오류를 잡아줌
    장점 2) SQL로 파싱 후 캐시 하기 때문에 파싱 비용이 별로 없다

    어떻게 사용

    1)어노테이션 2)XML에 정의 3)Spring data JPA 활용

    벌크연산

    PK로 찍어서 update,delete 제외한 나머지 모든 SQL 의 UPDate 문이나 delete 문
    JPA의 한건한건의 변경감지 대신 쿼리 한번으로 update 치기 가능

    예제

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

    주의점

    영속성 컨텍스트를 무시하고 db에 직접 쿼리 날리므로
    DB에는 update 되어 6000인데 영속성 컨텍스트에는 원래 값이 들어가 있는 경우가 있을 수 있다

    1)벌크 연산을 먼저 실행하거나

    2)벌크 연산 수행 후 영속성 컨텍스트를 초기화한다

    profile
    기록을 통해 실력을 쌓아가자

    0개의 댓글