본문 바로가기
  • 실행력이 모든걸 결정한다
Spring 사전 준비/JPA Hibernate

[JPA] Spring Data JPA(2)

by 김코더 김주역 2022. 8. 20.
반응형

1. 사용자 정의 리포지토리

- Repository의 메소드를 직접 구현해야 할 경우에는 사용자 정의 리포지토리를 추가하면 된다.

- 아래 3가지 절차를 걸쳐서 적용하면 된다.

 

i) 사용자 정의 리포지토리 생성

public interface CustomMemberRepository {
    // 메소드 정의
}

 

ii) 구현체 생성

- 사용자 정의 리포지토리 이름 뒤에 Impl가 붙은 구현체를 생성한다. Impl를 붙이지 않으면 Spring Data JPA가 인식하지 못한다.

public class CustomMemberRepositoryImpl implements CustomMemberRepository {
    // 메소드 구현
}

- 만약 Impl가 아닌 다른 키워드를 사용하고 싶다면 @Configuration 클래스에서 @EnableJpaRepositories.repositoryImplementationPostfix 속성에 원하는 키워드를 지정하면 된다.

 

iii) 사용자 정의 리포지토리 상속

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

 

 

 

2. @EnableSpringDataWebSupport

- Spring MVC에서 사용할 수 있는 편리한 기능을 제공해주는 어노테이션으로, @Configuration 클래스에 붙이면 적용된다.

@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
public class AppConfig {...}

 

1) 도메인 클래스 컨버터 기능

- 내부에 등록된 DomainClassConverter의 기능이다.

- URI로 들어온 식별자 파라미터를 통해 바로 엔티티를 반환해주는 기능이다.

@RequestMapping("/member")
public String member(@RequestParam("id") Member member, Model model) {...}

 

 

2) 페이징과 정렬 기능

- 내부에 등록된 HandlerMethodArgumentResolver의 기능이다.

- 컨트롤러 메소드의 파라미터로 Pageable을 받는다. Pageable은 page, size, sort 파라미터 정보로 만들어진다.

@RequestMapping("/members")
public String members(Pageable pageable, Model model) {...}
// 요청 예시 -> /members?page=4&size=25&sort=name,desc&sort=address.city

※ 기본값은 page=0, size=20이다. 기본값을 변경하고 싶다면 Pageable 앞에 @PageableDefault 어노테이션을 추가해서 지정하자.

※ 페이지는 기본적으로 0부터 시작된다. 페이지를 1부터 시작하고 싶다면 PageableHandlerMethodArgumentResolver를 bean으로 등록하고 setOneIndexedParameters를 true로 설정하면 된다.

 

- 사용해야 할 페이징 정보가 여러 개라면 @Qualifier 어노테이션으로 접두사를 만들어서 사용하면 된다. 요청 파라미터의 이름 앞에 "[접두사]_"를 붙여 구분하면 된다.

※ 예) member_page=3

@RequestMapping("/list")
public String list(
    @Qualifier("member") Pageable memberPageable,
    @Qualifier("team") Pageable teamPageable,
    Model model
) {...}

 

 

 

3. Spring Data JPA가 생성하는 리포지토리 구현체의 특징

- 등록/수정/삭제 메소드에 @Transactional이 적용되고, 조회 메소드에는 @Transactional(readOnly=true)이 적용된다.

- save() 메소드는 저장할 엔티티가 새로운 엔티티면 EntityManager.persist()를 호출하고 이미 있는 엔티티면 EntityManager.merge()를 호출한다. 새로운 엔티티라고 판단하는 기준은 엔티티의 식별자 값이 null이거나 0일 때다.

※ Persistable 인터페이스를 구현해서 새로운 엔티티를 판단 하는 로직을 변경할 수 있다.

 

 

 

4. Spring Data JPA와 QueryDSL 통합

- Spring Data JPA에서 QueryDSL을 지원하는 두 가지 방법을 살펴보자.

 

1) QueryDslPredicateExecutor

- 리포지토리에서 QueryDslPredicateExecutor 인터페이스를 상속받아서 사용할 수 있다. 

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

- QueryDslPredicateExecutor는 인자로 Predicate 객체가 들어가는 findAll(), findBy(), findOne(), count(), exists() 메소드를 지원한다.

※ QueryDslPredicateExecutor의 메소드들 : https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/querydsl/QuerydslPredicateExecutor.html

사용 예시

Qitem qitem = Qitem.item;
Iterable<Item> result = itemRepository.findAll(
    qitem.name.contains("LG").and(qitem.price.between(800000, 1300000);
);

- 문서에 나와 있듯이, findAll() 메소드에 Pageable이나 Sort 객체를 파라미터에 추가해서 페이징과 정렬 기능을 사용할 수도 있다.

- join, fetch 키워드를 사용할 수 없다는 단점이 있다.

 

 

2) QueryDslRepositorySupport

- JPQLQuery 객체를 반환하는 from() 메소드를 이용할 수 있게 되면서 QueryDsl의 모든 기능을 사용할 수 있게 되었다.

- QueryDslRepositorySupport의 메소드들 : https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/support/QuerydslRepositorySupport.html

사용 예시

public class OrderRepositoryImpl extends QueryDslRepositorySupport implements CustomOrderRepository {
    public OrderRepositoryImpl() {
        super(Order.class);
    }
 
    @Override
    public List<Order> search(OrderSearch orderSearch) {
        QOrder qorder = QOrder.order;
        QMember qmember = QMember.member;

        JPQLQuery query = from(qorder);

        if(StringUtils.hasText(orderSearch.getMemberName())) {
        query.leftJoin(qorder.member, qmember)
            .where(qmember.name.contains(orderSearch.getMemberName()));
        }

        if (orderSearch.getOrderStatus() != null) {
            query.where(qorder.status.eq(orderSearch.getOrderStatus()));
        }

        return query.list(qorder);
    }
}

 

 

 

● 참고자료 : 자바 ORM 표준 JPA 프로그래밍

 

 

반응형

'Spring 사전 준비 > JPA Hibernate' 카테고리의 다른 글

[JPA] JPA와 컬렉션  (0) 2022.08.24
[JPA] 웹 애플리케이션에서의 영속성 관리  (0) 2022.08.22
[JPA] Spring Data JPA(1)  (0) 2022.08.19
[JPA] JPQL 최적화  (0) 2022.08.14
[JPA] 스토어드 프로시저  (0) 2022.08.14

댓글