-
스프링 데이터 JPA스프링/스프링 기초DB 2023. 3. 26. 17:03
스프링 데이터 JPA는 JPA 기술을 더 편리하게 사용할 수 있도록 스프링 프레임워크에서 지원하는 기능이다.
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); }
스프링 데이터 Jpa를 사용한 ItemRepository 인터페이스이다.
스프링 데이터 Jpa의 특징은 인터페이스를 만들면 많이 사용하면 save, update, findAll 등의 기능은 스프링 데이터 JPA가 기본으로 구현해준다. 별도로 구현체를 만들지 않아도 된다. 또한, 많이 사용하는 기능 이외에 별도로 사용해야 하는 기능이 있을 때가 있다. 위에 코드처럼 검색을 할 때 조건을 걸어서 일부만 검색한다고 할 때, findByItemName 등으로 규칙적인 메서드 이름을 만들면 스프링 데이터 JPA가 알아서 해당 내용의 기능을 구현해준다.
- 조회: find…By , read…By , query…By , get…By
- 예:) findHelloBy 처럼 ...에 식별하기 위한 내용(설명)이 들어가도 된다. - COUNT: count…By 반환타입 long
- EXISTS: exists…By 반환타입 boolean
- 삭제: delete…By , remove…By 반환타입 long
- DISTINCT: findDistinct , findMemberDistinctBy
- LIMIT: findFirst3 , findFirst , findTop , findTop3
위의 기능들은 메서드 이름으로 만들면 스프링 데이터 JPA가 구현을 자동으로 해준다.
하지만 메서드 이름이 너무 길어져서 이런 방식을 사용하고 싶지 않을 때에는 @Query 애노테이션으로 JPQL을 작성하면 되고 이 때에는 메서드 이름으로 자동 구현해주는 기능은 무시된다.
하지만 ItemService는 ItemRepository에 의존하기 때문에 ItemService에서 SpringDataJpaItemRepository를 그대로 사용할 수는 없다. 때문에 ItemRepository를 구현하는 클래스를 하나 만들어서 사용해야한다. 그렇지 않으면 ItemService의 코드 변경이 필요할 것이다.
@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.setItemNameBy(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.findByItemNameLikeAndPriceLessThanEqual("%" + itemName + "%", maxPrice); 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(); } // Querydsl이 있으면 동적 쿼리는 이렇게 작성 안한다. } }
동적 쿼리를 사용하면 findAll()을 제외하고는 코드가 훨씬 간결해진 것을 볼 수 있다.
SpringDataJpaConfig.class
@Configuration @RequiredArgsConstructor public class SpringDataJpaConfig { private final SpringDataJpaItemRepository springDataJpaItemRepository; @Bean public ItemService itemService() { return new ItemServiceV1(itemRepository()); } @Bean public ItemRepository itemRepository() { return new JpaItemRepositoryV2(springDataJpaItemRepository); } }
의존관계를 수정하고 테스트코드에서 실행해보니 잘 되는 것을 확인할 수 있다.
다른 기술들은 구현하기 어렵고 복잡한 반면에 스프링 데이터 JPA를 사용하면 반복작업을 최소화해서 기능들을 사용할 수 있다.
'스프링 > 스프링 기초DB' 카테고리의 다른 글
트랜잭션 AOP 주의사항 - 프록시 내부 호출 (0) 2023.04.01 데이터 접근 기술 - Querydsl (0) 2023.03.28 데이터 접근 기술 - JPA (0) 2023.03.26 db 테스트에서의 트랜잭션 (0) 2023.03.25 스프링 예외 추상화 (0) 2023.03.19 - 조회: find…By , read…By , query…By , get…By