🌿SPRING/🍀공부 [SPRING]

[SPRING][JPA] @Query 활용하기

디카페인라떼 2022. 9. 29. 12:58

패스트 캠퍼스의 강의 [한 번에 끝내는 Java/Spring 웹 개발 마스터 초격차 패키지]를 보고 정리한 글입니다.


@Query란?
Query Method 의 커스텀 버전!
  • 일반적으로 @Query까지는 필요가 없으나 2가지의 경우 @Query를 쓰는 게 더 낫다
    • 긴 쿼리메소드의 이름을 가독성이 좋게 수정이 필요한 경우
    • 엔티티 전체가 아닌 필요한 컬럼만 부분적으로 조회가 필요한경우

1. Query Method의 가독성 문제
= Query Method의 이름의 길이가 길 경우
  • 여러가지 조건이 있는 경우 메소드명이 길어질 수 밖에 없음.
  •  ex)findByCatrgoryIsNullAndName....
더보기

 Test 해보는 경우 ->쿼리가 잘 생성되었지만 값이 안나올 수 있음 -> 디버깅 -> 조건이 null 값이 들어가있음..

  •  코드 상 수정 가능 ...
    => 테스트에서 사전에 문제가 있음을 확인할 수 있도록 코딩하는 것이 중요
    • 수정방법 (조건을 추가해줌)
      •  data.sql을 고침
        • 그러면 계속 data를 넣어줄때마다 계속 조건부분을 넣어줘야함.. (null이 생길수 있음)
      •  entity에 추가해주기
        • @Column(columnDefinition="디폴트 값을 지정") /
        • =>Auto DDL의 속성 
        • => sql type을 치환하는 것 / 각각의 속성이 이어 붙음 (유효성 확인 안함)
        • =>comment: 로 주석 처리도 가능
  • 이렇게 쿼리메소드명이 긴 경우 where 절이 어떻게 작용하는지 알기 어려움.
    • @Query를 사용하면 된다!
@Query(value = "select b from Book b where name = ?1 and createdAt >= ?2 and updateAt >= ?3 and category is null")
List<book> findByRecently (String name, LocalDateTime createdAt, LocalDateTime updateAt);
  • 쿼리를 만들때 매개변수를 넣어주는 방법
    1. ?1 , ?2 ,?3 이라는 ?숫자를 사용 해당 메소드에서 몇번째에 있는 파라미터값인지를 치환함 (1base index 이므로 1부터 시작함)
      • (value = "select b from Book b where name = ?1 and createdAt >= ?2 and updateAt >= ?3 and category is null")
      • 꼭 파라미터 순서가 순차적일 필요는 없음. 숫자로 매핑해주는 방식임.(그러나 되도록 순차적으로)
      • 자바에서는 순서에 의존성을 가지는 파라미터 매핑 방식은 지양함
        • 언제든 파라미터가 추가되거나 하면서 사이드 이펙트의 확률이 높아짐.
    2. (조금더 권장하는 방식) name 기반의 파라미터 매핑
@Query(value = "select b from Book b where name = :name and createdAt >= :createdAt and updateAt >= :updateAt and category is null")
List<book> findByRecently (@Param("name") String name, @Param("createdAt") LocalDateTime createdAt, @Param("updateAt") LocalDateTime updateAt);
  •  @Param("name") String name. ... 이런식
  • 매개변수의 순서에 영향을 받지 않기 때문에 추가가되거나 사이드이펙트에서 좀 더 자유로움

 

🚨중요한 점 : JPQL !🚨

  • JPA entity를 기반으로 하는 쿼리를 생성
  • java 객체를 활용할수 있는 sql 구문!
  • Table 이름이 아닌 Entity로
  • Entity내에 존재하는 field이름
  • JPQL의 장점
    • 방언 dialect : 방언을 통해서 DB의 종류에 따라 서로다른 쿼리를 자동으로 생성해줌
    •  native 쿼리와 차이가 있음
    • 실제로는 쿼리메소드로 만드는 것과 비슷한 과정으로 생성

2. 엔티티에 연결되지 않은 쿼리가 가능함.
=> 필요한 컬럼들만 추려서 조회가 가능함.
	@Query(value = "select b.name as name, b.category as category from Book b")
	List<BookNameAndCategory> findBookNameAndCategory();
  • 이런 식으로 필요한 컬럼만 추려서 조회 가능함.

 

👀 java 객체를 활용할 수 있는 sql 구문도 있음!

	@Query(value = "select new com....(풀네임 적기)BookNameAndCategory(b.name, b.category) from Book b") => 가능함!
	List<BookNameAndCategory> findBookNameAndCategory();
  • 객체생성해서도 가능하지만 com.xxxx.xxxx...entity 이런식으로 풀네임을 적어줘야함.

 


추가적으로 @Query를 좀더 잘 활용할 수 있는 방법!
: Pagable : 자동적으로 페이징하는 것
@Query(value = "select b.name as name, b.category as category from Book b")
Page<BookNameAndCategory> findBookNameAndCategory(Pagable pagable);

☝메세지 오버로딩 : 메소드명은 같지만 파라미터가 다르면 둘다 선언 가능함. 이를 메세지 오버로딩이라고 함.

 


🚩@Query를 사용함으로써

  1. 긴 쿼리메소드의 이름을 가독성이 좋게 수정 가능
  2. 엔티티 전체가 아닌 필요한 컬럼만 부분적으로 추출하여 조회 가능
    • 추출할때는 인터페이스형식 / DTO 형식으로 클래스를 선언하여서 추출 가능
  3. 페이징 기능도 아주 쉽게 추가할수 있도록 지원

 

🧨다만 JPA 이 문법이 어려워서 JPQL을 사용하는 것 보다는 각각의 용도에 맞는 쓰임새가 있으므로 각각의 방법을 숙지하고 적절한 때에 사용하기!