관리 메뉴

ballqs 님의 블로그

[Spring] JpaRepository 쿼리 사용 방법 및 효율적으로 사용 방법 본문

코딩 공부/Spring

[Spring] JpaRepository 쿼리 사용 방법 및 효율적으로 사용 방법

ballqs 2024. 9. 26. 19:21

JpaRepository 쿼리 사용 방법

리턴타입 {접두어}{도입부}By{프로퍼티 표현식}(조건식)[(And|Or){프로퍼티 표현식}(조건식)](OrderBy{프로퍼티}Asc|Desc) (매개변수...)

접두어 Find, Count, ...
도입부 Distinct, First(N), Top(N)
프로퍼티 표현식 Person.Address.ZipCode => find(Person)ByAddress_ZipCode(...)
조건식 IgnoreCase, Between, LessThan, GreaterThan, Like, Contains, ...
정렬 조건 OrderBy{프로퍼티}Asc|Desc
리턴 타입 E, Optional<E>, List<E>, Page<E>, Slice<E>, Stream<E>
매개변수 Pageable, Sort

 

쿼리 실습 코드

// 기본
List<User> findByNameAndPassword(String name, String password);

// distinct (중복제거)
List<User> findDistinctUserByNameOrPassword(String name, String password);
List<User> findUserDistinctByNameOrPassword(String name, String password);

// ignoring case (대소문자 무시)
List<User> findByNameIgnoreCase(String name);
List<User> findByNameAndPasswordAllIgnoreCase(String name, String password);

// 정렬
List<Person> findByNameOrderByNameAsc(String name);
List<Person> findByNameOrderByNameDesc(String name);

// 페이징
Page<User> findByName(String name, Pageable pageable);  // Page 는 카운트쿼리 수행됨
Slice<User> findByName(String name, Pageable pageable); // Slice 는 카운트쿼리 수행안됨
List<User> findByName(String name, Sort sort);
List<User> findByName(String name, Pageable pageable);

// 스트림 (stream 다쓴후 자원 해제 해줘야하므로 try with resource 사용추천)
Stream<User> readAllByNameNotNull();

JpaRepository 효율적으로 사용 방법

Optional 제거하기

Spring Data JPA의 findByXX 메서드는 기본적으로 Optional을 반환한다. 이로 인해 비즈니스 로직에서 Optional 처리를 위한 추가적인 작업이 필요하게 되는데, 이럴 때 default 메서드를 활용하면 이 문제를 우아하게 해결할 수 있다.

public interface UserRepository extends JpaRepository<User, Long> {
    // Default 메소드를 사용하여 findById의 Optional을 내부적으로 처리
    default User findUserById(Long id) {
        return findById(id).orElseThrow(() -> new DataNotFoundException("User not found with id: " + id));
    }
}

 

메서드명 간소화하기

Spring Data JPA를 사용하다 보면 복잡한 쿼리 때문에 메서드명이 길어져 가독성을 해치는 경우가 있다. 이럴 때도 default 메서드를 활용하면 긴 메서드명을 간결하고 명확하게 표현할 수 있다.

public interface ProductRepository extends JpaRepository<Product, Long> {
    // 기존의 긴 쿼리 메소드
    List<Product> findAllByCategoryAndPriceGreaterThanEqualAndPriceLessThanEqualOrderByPriceAsc(String category, BigDecimal minPrice, BigDecimal maxPrice);

    // Default 메소드를 사용하여 간결한 메소드명 제공
    default List<Product> findProductsByCategoryAndPriceRange(String category, BigDecimal minPrice, BigDecimal maxPrice) {
        return findAllByCategoryAndPriceGreaterThanEqualAndPriceLessThanEqualOrderByPriceAsc(category, minPrice, maxPrice);
    }
}

 

비즈니스 로직 통합

여러 기본 제공 메서드를 하나의 고차 작업으로 결합할 수도 있다. 다만 Spring Data JPA의 Repository는 Data Access Layer의 일부로, 데이터베이스와의 상호작용만을 담당하는 것이 일반적이기 때문에 이 부분은 서비스 레이어에서 처리하는 것이 일반적이다.

public interface UserRepository extends JpaRepository<User, Long> {

    // 사용자 ID로 사용자를 찾고, 존재할 경우 연락처 정보를 업데이트하는 메소드
    default void updateUserContact(Long userId, String newContact) {
        findById(userId).ifPresent(user -> {
            user.setContact(newContact);
            save(user);
        });
    }
}

'코딩 공부 > Spring' 카테고리의 다른 글

[Spring] Redis pub/sub란?  (0) 2024.10.07
[Spring] @Async 란?  (0) 2024.10.04
[Spring] JPA 매핑 기능  (0) 2024.09.26
[Spring] @TransactionalEventListener란?  (0) 2024.09.20
[Spring] @Mock , @MockBean 의 차이점  (0) 2024.09.14