[Spring Database] Spring Data JPA
스프링 데이터 JPA 기술의 가장 대표적인 기능은 두 가지이다.
1. 공통 인터페이스
2. 쿼리 메서드
JpaRepository 인터페이스는 기본적인 CRUD 및 공통화가 가능한 기능들을 모두 제공한다.
JpaRepository 인터페이스를 사용할 리포지토리에서 상속받고(extends), 제네릭에 관리할 <Entity, EntityId>를 입력해주면 스프링 데이터 JPA 기술 내부에서 프록시 기술을 통해 구현 클래스가 생성된다.
만들어진 구현 클래스의 인스턴스는 스프링 빈으로 등록되고, 개발자는 구현 클래스를 신경쓰지 않고 JpaRepository 인터페이스가 제공하는 기술을 사용할 수 있다.
인터페이스에 메서드만 적어두면 스프링 데이터 JPA 기술이 메서드 이름을 분석해 쿼리를 자동으로 만들고 실행해준다.
JPA만 사용했을 경우 복잡한 쿼리를 보낼 때 JPQL을 직접 작성하고 파라미터 바인딩도 해 줘야 했지만,
스프링 데이터 JPA는 메서드 이름을 분석해 필요한 JPQL을 만들고 실행해준다.
(메서드 이름은 규칙에 맞게 작성해야 한다)
직접 JPQL을 작성하고 싶을 때는 @Query 애너테이션에 JPQL을 넣어 주면 된다.
public interface SpringDataJpaItemRepository extends JpaRepository<Item, Long> {
List<Item> findByItemNameLike(String itemName);
List<Item> findByPriceLessThanEqual(Integer price);
//쿼리 메서드 (아래 메서드와 같은 기능)
List<Item> findByItemNameLikeAndPriceLessThanEqual(String itemName, Integer price);
//쿼리 직접 실행
@Query("select i from Item i where i.itemName like :itemName and i.price <= :price")
List<Item> findItems(@Param("itemName") String itemName, @Param("price") Integer price);
}
상품을 이름으로 검색하거나 가격으로 검색하는 기능은 공통으로 처리할 수 없다.
쿼리 메서드 혹은 @Query 애너테이션을 사용하자.
@Query 애너테이션을 사용하지 않는 경우 스프링 데이터 JPA가 메서드 이름을 분석해 JPQL을 만들어서 실행한다.
애너테이션을 사용해 쿼리를 직접 사용할 경우 @Param 애너테이션으로 파라미터를 명시적으로 바인딩 해 주자.
ItemService는 ItemRepository에 의존한다.
ItemService의 수정 없이 SpringDataJpaItemRepository를 사용하기 위해 JpaItemRepositoryV2를 도입하자.
JpaItemRepositoryV2는 ItemRepository의 구현체이고, SpringDataJpaItemRepository를 사용한다.
JpaItemRepositoryV2를 어댑터처럼 사용한다.
@Repository
@Transactional
@RequiredArgsConstructor
public class JpaItemRepositoryV2 implements ItemRepository {
private final SpringDataJpaItemRepository repository;
@Override
public Item save(Item item) {
return repository.save(item);
}
@Override
public void update(Long itemId, ItemUpdateDto updateParam) {
Item findItem = repository.findById(itemId).orElseThrow();
findItem.setItemName(updateParam.getItemName());
findItem.setPrice(updateParam.getPrice());
findItem.setQuantity(updateParam.getQuantity());
}
@Override
public Optional<Item> findById(Long id) {
return repository.findById(id);
}
@Override
public List<Item> findAll(ItemSearchCond cond) {
String itemName = cond.getItemName();
Integer maxPrice = cond.getMaxPrice();
// 동적쿼리
if (StringUtils.hasText(itemName) && maxPrice != null) {
return repository.findItems("%" + itemName + "%", maxPrice);
} else if (StringUtils.hasText(itemName)) {
return repository.findByItemNameLike("%" + itemName + "%");
} else if (maxPrice != null) {
return repository.findByPriceLessThanEqual(maxPrice);
} else {
return repository.findAll();
}
}
}
스프링 데이터 JPA 기술이 제공하는 메서드들을 사용해 작업을 처리한다.
혹시나 예외가 발생해도 프록시에서 예외를 변환 해 주기 때문에 @Repository 애너테이션에 상관없이 예외가 변환된다.
findAll 부분은 공통으로 제공하는 기능이 아니라서 별도로 작성한 메서드를 사용한다.
조건이 2개인데도 참 복잡하다. 메서드 이름도 길어지고.. 조건이 더 많아질수록 문제가 심각해진다.
스프링 데이터 JPA는 동적 쿼리에 관련된 지원이 약하다. 추후 QueryDSL 기술을 사용해 동적 쿼리 부분을 개선해보자.
'Spring > Spring Database' 카테고리의 다른 글
[Spring Database] 트랜잭션 (0) | 2022.09.13 |
---|---|
[Spring Database] QueryDSL (1) | 2022.09.11 |
[Spring Database] JPA 적용 (0) | 2022.09.10 |
[Spring Database] JPA (1) | 2022.09.09 |
[Spring Database] MyBatis (0) | 2022.09.09 |
댓글
이 글 공유하기
다른 글
-
[Spring Database] 트랜잭션
[Spring Database] 트랜잭션
2022.09.13 -
[Spring Database] QueryDSL
[Spring Database] QueryDSL
2022.09.11 -
[Spring Database] JPA 적용
[Spring Database] JPA 적용
2022.09.10 -
[Spring Database] JPA
[Spring Database] JPA
2022.09.09