본문 바로가기
TIL

TIL내일배움캠프 13주차 JPA심화 JPA 자동 쿼리 생성

by 율량동박씨 2024. 7. 10.

오늘의 키워드

  • JPA 자동 쿼리 생성
  • JpaRepository 쿼리 기능
  • Spring Data JPA
  • Optional 처리
  • 메서드명 간소화
  • 비즈니스 로직 통합

오늘의 내용

  • 테이블 객체로 자동 쿼리 생성
  • JpaRepository 쿼리 기능
    • Spring Data Common의 CRUDRepository + PagingAndSortingRepository 쿼리 기능 제공.
    • Repository는 Marker Interface로 특별한 기능은 없음.
    • Repository ~ JpaRepository는 @NotRepositoryBean이 붙어있는 인터페이스.
    • JpaRepository<Entity, ID>를 사용하면 SimpleJpaRepository 구현체 빈이 등록됨.

2. 쿼리 실습 코드

기본

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 사용 후 자원 해제 필요)
Stream<User> readAllByNameNotNull();
  • JpaRepository 효율적으로 사용하는 방법
  • Optional 제거하기
    • findByxx 메서드는 기본적으로 Optional을 반환.
    • Default 메서드를 활용하여 내부적으로 Optional을 처리.
public interface UserRepository extends JpaRepository<User, Long> {
default User findUserById(Long id) {
return findById(id).orElseThrow(() -> new DataNotFoundException("User not found with id: " + id));
	}
}
 
  • 메서드명 간소화하기
  • 복잡한 쿼리 때문에 메서드명이 길어지는 경우 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의 일부로, DB와 상호작용만을 담당.
    • 비즈니스 로직은 일반적으로 서비스 레이어에서 처리.

Spring Data JPA의 주요 기능과 사용법

JpaRepository 인터페이스

  • JpaRepository는 PagingAndSortingRepository와 CRUDRepository를 확장하여 페이징 및 정렬 기능을 제공.
  • 다양한 기본 CRUD 메서드를 제공하여 기본적인 데이터베이스 작업을 쉽게 수행 가능.

페이징과 정렬

  • 페이징 기능을 사용하여 데이터베이스의 대용량 데이터를 효율적으로 처리.
  • Pageable 객체를 사용하여 페이징과 정렬을 함께 처리 가능.
  • Sort 객체를 사용하여 특정 필드를 기준으로 정렬 가능.
Page<User> findAll(Pageable pageable); List<User> findAll(Sort sort);
 

쿼리 메서드 생성 규칙

  • 메서드 이름을 기반으로 쿼리를 생성.
  • findBy, readBy, queryBy, getBy, countBy, existsBy 등의 접두어 사용.
  • 조건자를 사용하여 다양한 조건을 추가 가능 (And, Or, Is, Equals, Between, LessThan, GreaterThan, Like, In, Not, IgnoreCase 등).
List<User> findByNameAndPassword(String name, String password);
List<User> findByNameIgnoreCase(String name);
 

실습 예제

UserRepository.java

public interface UserRepository extends JpaRepository<User, Long> {
	List<User> findByNameAndPassword(String name, String password);
    List<User> findByNameIgnoreCase(String name);
    List<User> findByNameOrderByNameAsc(String name);
    Page<User> findByName(String name, Pageable pageable);
}
 

UserService.java

@Service
public class UserService {

	private final UserRepository userRepository;
    
	@Autowired
	public UserService(UserRepository userRepository) {
    	this.userRepository = userRepository;
        }
        
    public List<User> findUsersByNameAndPassword(String name, String password) {
    return userRepository.findByNameAndPassword(name, password);
    }
    
    public List<User> findUsersByNameIgnoreCase(String name) {
    return userRepository.findByNameIgnoreCase(name);
    }
    
    public List<User> findUsersByNameOrderByNameAsc(String name) {
    return userRepository.findByNameOrderByNameAsc(name);
    }
    
    public Page<User> findUsersByName(String name, Pageable pageable) {
    return userRepository.findByName(name, pageable);
    }
}