ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 데이터 접근 기술- Spring Data JPA
    BackEnd/Spring DB 2023. 2. 4. 08:05
    반응형

      Spring Data JPA는 JPA를 편리하게 사용할 수 있도록 도와주는 라이브러리입니다. Spring Data JPA에 대해 이전에 다룬 내용이 있어 다음 링크를 참고하시면 됩니다. 이번 포스팅에서는 Spring Data JPA의 대표적인 기능과 진행 중인 프로젝트에 Spring Data JPA를 적용해 보겠습니다.

     

     

    Spring Data JPA 대표 기능

    공통 인터페이스 기능

      JpaRepository 인터페이스를 통해서 기본적인 CRUD 기능을 제공합니다.

     

    JpaRepository 사용법

      JpaRepository 인터페이스를 상속 받고, 제네릭에 관리할 <엔티티, 엔티티ID>를 주면 됩니다. JpaRepository 인터페이스만 상속받으면 Spring Data JPA가 프록시 기술을 사용해서 구현 클래스를 만들고, 구현 클래스의 인스턴스를 만들어 스프링 빈으로 등록합니다.

    public interface ItemRepository extends JpaRepository<Member, Long> {...}

     

    쿼리 메서드 기능

      Spring Data JPA는 인터페이스에 메서드만 적어두면 메서드 이름을 분석해서 쿼리를 자동으로 만들고 실행해주는 기능을 제공합니다.

    public interface MemberRepository extends JpaRepository<Member, Long> {
            List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
    }

    스프링 데이터 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

     

      쿼리 메서드 기능에 대한 상세 내용은 다음 링크를 참고하시면 됩니다.

    Spring Data JPA 공식 문서

     

    @Query

      쿼리 메서드 기능 대신에 직접 JPQL 또는 네이티브 쿼리를 사용하고 싶을 때는 @Query와 함께 작성하면 됩니다. 이때는 메서드 규칙은 무시됩니다.

    public interface SpringDataJpaItemRepository extends JpaRepository<Item, Long> {
    
        //쿼리 메서드 (아래 메서드와 같은 기능 수행)
        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);
    }

     

    Spring Data JPA 적용

    의존성 추가(build.gradle)

    //JPA, 스프링 데이터 JPA 추가
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

     

      다음으로 JpaRepository 인터페이스를 상속 받는 인터페이스를 정의합니다. 기본적인 CRUD 기능을 사용할 수 있습니다.

    package hello.itemservice.repository.jpa;
    
    import hello.itemservice.domain.Item;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.Query;
    import org.springframework.data.repository.query.Param;
    
    import java.util.List;
    
    public interface SpringDataJpaItemRepository extends JpaRepository<Item, Long> {
    
        //select i from Item i where i.name like ?
        List<Item> findByItemNameLike(String itemName);
    
        //select i from Item i where i.price <= ?
        List<Item> findByPriceLessThanEqual(Integer price);
    
        //쿼리 메서드 (아래 메서드와 같은 기능 수행)
        //select i from Item i where i.itemName like ? and i.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);
    }

     

      다음은 ItemRepository의 구현체와 Config 파일을 만들고 적용하는 코드입니다.

    package hello.itemservice.repository.jpa;
    
    import hello.itemservice.domain.Item;
    import hello.itemservice.repository.ItemRepository;
    import hello.itemservice.repository.ItemSearchCond;
    import hello.itemservice.repository.ItemUpdateDto;
    import lombok.RequiredArgsConstructor;
    import org.springframework.stereotype.Repository;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.util.StringUtils;
    
    import java.util.List;
    import java.util.Optional;
    
    @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.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();
            }
        }
    }
    package hello.itemservice.config;
    
    import hello.itemservice.repository.ItemRepository;
    import hello.itemservice.repository.jpa.JpaItemRepositoryV2;
    import hello.itemservice.repository.jpa.SpringDataJpaItemRepository;
    import hello.itemservice.service.ItemService;
    import hello.itemservice.service.ItemServiceV1;
    import lombok.RequiredArgsConstructor;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @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);
        }
    
    }
    @Import(SpringDataJpaConfig.class)
    @SpringBootApplication(scanBasePackages = "hello.itemservice.web")
    public class ItemServiceApplication {}

     

    Spring Data JPA 예외

      Spring Data JPA은 스프링 예외 추상화를 지원합니다. Spring Data JPA가 만들어주는 프록시에서 이미 예외 변환을 처리하기 때문에 @Repository와 관계 없이 예외가 변환됩니다.

     

    [참고 정보]

    스프링 DB 2편 - 데이터 접근 핵심 원리

    전체 소스코드

    반응형

    'BackEnd > Spring DB' 카테고리의 다른 글

    데이터 접근 기술- 활용  (0) 2023.02.09
    데이터 접근 기술- QueryDSL  (0) 2023.02.04
    데이터 접근 기술- JPA  (2) 2023.02.04
    데이터 접근 기술- MyBatis  (0) 2023.02.02
    데이터 접근 기술- 스프링 JdbcTemplate  (0) 2023.02.01

    댓글

Designed by Tistory.