▶ 제08장. Spring Data JPA 활용
- JPQL(JPA Query Language)
- JPA에서 사용할 수 있는 쿼리를 의미
- 예시 -> select p from Product p where p.number =?1;
- Product : 엔티티 이름
- p.nuber : 엔티티 속성
- 쿼리 메서드
- JpaRepository에서 상속받은 기본 메서드 이외의 별도 메서드를 정의해서 사용할 경우 간단하게 쿼리문을 작성하기 위해 사용
- 쿼리 메서드의 생성법 (동작을 결정하는 주제와 서술어로 구분)
- find... By, exist... By, get... By,,, 등과 같은 키워드로 쿼리 주제를 정함
- By : 서술어의 시작을 나타내는 구분자 역할
- 서술어 부분은 검색 및 청렬 조건을 지정
- 엔티티 속성으로 정의할 수 있으며 AND나 OR를 사용해 조건 확장 가능
- 엔티티에서 관리하고 있는 속성(필드)만 참조 가능
- 예시 -> List <Person> findByLastnameAndEmail(String lastName, String email);
- 주제 키워드
- 조건자 키워드
- Is: 값의 일치를 조건으로 사용
- 생량 되는 경우도 많으며, Equals와 동일한 기능을 수행
- 예시 ->
- Product findByNumberIs(Long number);
- Product findByNumberEquals(Long number);
- (Is) Not: 값의 불일치를 조건으로 사용
- (Is) Null, (Is) NotNull: 값이 null인지 검사
- (Is) True, (Is) NotTrue: boolean타입으로 지정된 칼럼값을 확인
- Or, And: 여러 조건을 묶을 때 사용
- (Is) GreaterThan, (Is) LessThan, (Is) Between:숫자나 datetime 칼럼을 대상으로 한 비교 연산에 사용
- (Is) StartingWith(==StartsWith), (Is) EndingWith(==EndsWith), (Is) Containing(==Contains), (Is) Like: 칼럼값에서 일부 일치 여부를 확인
- Is: 값의 일치를 조건으로 사용
- 정렬과 페이징 처리
- 정렬 처리
- 쿼리 메서드 정렬 처리
- 예시 -> List <Product> findByNameorderByPriceAscStockDesc(String name);
- Price를 기중으로 오름차순 정렬 후 후순위로 재고수량을 기준으로 내림차순 정렬
- 매개변수를 활용한 쿼리 정렬
- 예시 -> List findByNameorder(String name, Sort sort);
- 쿼리 메서드 정렬과 거의 같은 기능을 수행
- 차이점은 Sort로 받은 정렬 기준을 가지고 쿼리문에 적용
- 호출에서 예시 -> productRepository.findByName("펜", Sort.by(Order.asc("price"), Order.desc("stock")));
- 쿼리 메서드 정렬 처리
- 페이징 처리
- DB의 레코드를 개수로 나눠 페이지를 구분하는 것
- 리턴 타입으로 Page를 설정하고 매개변수에는 Pageable 타입을 정의해서 사용
- 예시 -> Page <Product> findByName(String name, Pageable, pageable);
- 호출할 때 리턴 타임으로 Page객체를 받고, Pageable 파라미터 전달을 위해 PageRequest클래스 사용
- 호출에서 예시 -> Page <Product> productPage = productRepository.findByName("펜", PageRequest.of(0, 2));
- PageRequest의 매개변수
- of(int page, int size): 페이지 번호(0부터 시작), 페이지당 데이터 개수
- of(int page, int size, Sort): 페이지 번호, 페이지당 데이터 개수, 정렬
- of(int page, int size, Derection, String properties): 페이지 번호, 페이지당 데이터 개수, 정렬 방향, 속성(칼럼)
- 정렬 처리
- @Query 어노테이션 사용하기
- 직접 JPQL을 작성할 수 있는 방식
- JPA 구현체에서 자동으로 쿼리 문장을 해석하고 실행
- 예시 -> @Query("select p From Product As p where p.name = ?1"
List<Product> findBy Name(String name); - @Param 어노테이션과 함께 사용하면 ?의 순서 신경 없어 오류 발생 적어짐
- 예시 -> @Query("select p From Product As p where p.name = :name"
List findBy Name(@Param("name") String name);
- 예시 -> @Query("select p From Product As p where p.name = :name"
- QueryDSL 적용하기
- @Query는 메서드 이름 기반 JPQL의 한계는 대부분 해소 가능하지만, 직접 문자열을 입력하기 때문에 오타와 같은 에러가 발생해 런타임 에러가 발생한다.(컴파일 시점에는 에러가 잡히지 않는다) 이를 방지하기 위해 QueryDSL을 사용
- QueryDSL 장점
- IDE에서 자동 완성을 사용 가능
- 문법적으로 잘못된 쿼리를 허용하지 않음
- 고정된 SQL 쿼리를 작성하지 않기 때문에 동적으로 쿼리를 생성할 수 있음
- 코드로 작성하므로 가독성 및 생산성 향상
- 도메인 타입과 프로퍼티를 안전하게 참조 가능
- 사용을 위해서 의존성 주입, plugins에 추가가 필요
- Maven(complie), Gradle(other -> complieQuertdsl) 눌러 빌드해주면 작성했던 모든 엔티티 클래스의 Qdomain이라는 쿼리 타입의 클래스를 자체적으로 생성해서 메타데이터로 사용해서 SQL을 작성
- 리턴 타입
- List<T> fetch(): 조회 결과를 리스트로 반환
- T fetchOne(): 단 건의 조회 결과를 반환
- T fetchFirst(): 여러 건의 조회 결과 중 1건을 반환(내부 로직: .limit(1).fetchOne())
- Long fetchCount(): 조회 결과의 개수를 반환
- QueryResult<T> fetchResults(): 조회 결과 리스트와 개수를 포함한 QueryResults를 반환
- 사용법
- JPAQuery<Product> query = new JPAQuery(entityManager);
- from 절부터 작성
- JPAQueryFactory query = new JPAQueryFactory(entityManager);
- select절부터 작성 가능
- JPAQuery<Product> query = new JPAQuery(entityManager);
- [한걸음 더]JPA Auditin 적용
- Spring Data JPA에서 엔티티 클래스에는 공통적으로 들어가는 필드들을 자동으로 넣어주는 기능
- 생성 주체, 생성 일자, 변경 주체, 병경 일자
- @SpringBootApplication있는 곳, 아니면 별도의 @Configuration클래스에 @EnableJpaAuditing 어노테이션추가해서 사용(후자의 방법을 권장)