스프링 데이터 JPA 소개
- 스프링 데이터 JPA는 스프링 프레임워크에서 JPA를 편리하게 사용할 수 있도록 지원하는 프로젝트
- CRUD 처리를 위한 공통 인터페이스를 제공 -> 데이터 접근 계층을 개발할 때 구현 클래스 없이 인터페이스만 작성해도 개발을 완료할 수 있음
- save(), findOne(), findAll() 등등 일반적은 CRUD메소드는 JpaRepository 인터페이스가 공통으로 제공하므로 개발자가 구현하지 않아도 된다.
- 스프링 프레임워크와 JPA를 함께 사용한다면 스프링 데이터 JPA 사용을 적극 추천
public interface MemberRepository extends JpaRepository<Member, Long> {
}
공통 인터페이스 기능
- 스프링 데이터 JPA는 간단한 CRUD 기능을 공통으로 처리하는 JpaRepository 인터페이스를 제공한다.
- JpaRepository 인터페이스 계층 구조
- 윗부분에 스프링 데이터 모듈이 있고 그 안에 Repository, CrudRepository, PagingAndSortingRepository가 있는데 이것은 스프링 데이터 프로젝트가 공통으로 사용하는 인터페이스이다.
JpaRepository 인터페이스는 여기에 추가로 JPA에 특화된 기능을 제공한다. - save(S), delete(T), findOne(ID), getOne(ID), findAll(...) ... 등 JpaRepository 인터페이스를 상속받으면 사용할 수 있는 주요 메소드들이 있다.
- 윗부분에 스프링 데이터 모듈이 있고 그 안에 Repository, CrudRepository, PagingAndSortingRepository가 있는데 이것은 스프링 데이터 프로젝트가 공통으로 사용하는 인터페이스이다.
쿼리 메소드 기능
1. 메소드 이름으로 쿼리 생성
- 메소드 이름만으로 쿼리를 생성해준다.
- 정해진 규칙
Keyword | Sample | JPQL snippet |
And |
findByLastnameAndFirstname |
… where x.lastname = ?1 and x.firstname = ?2 |
Or |
findByLastnameOrFirstname |
… where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals |
findByFirstname,findByFirstnameIs,findByFirstnameEquals |
… where x.firstname = 1? |
Between |
findByStartDateBetween |
… where x.startDate between 1? and ?2 |
LessThan |
findByAgeLessThan |
… where x.age < ?1 |
LessThanEqual |
findByAgeLessThanEqual |
… where x.age ⇐ ?1 |
GreaterThan |
findByAgeGreaterThan |
… where x.age > ?1 |
GreaterThanEqual |
findByAgeGreaterThanEqual |
… where x.age >= ?1 |
After |
findByStartDateAfter |
… where x.startDate > ?1 |
Before |
findByStartDateBefore |
… where x.startDate < ?1 |
IsNull |
findByAgeIsNull |
… where x.age is null |
IsNotNull,NotNull |
findByAge(Is)NotNull |
… where x.age not null |
Like |
findByFirstnameLike |
… where x.firstname like ?1 |
NotLike |
findByFirstnameNotLike |
… where x.firstname not like ?1 |
StartingWith |
findByFirstnameStartingWith |
… where x.firstname like ?1 (parameter bound with appended %) |
EndingWith |
findByFirstnameEndingWith |
… where x.firstname like ?1 (parameter bound with prepended %) |
Containing |
findByFirstnameContaining |
… where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy |
findByAgeOrderByLastnameDesc |
… where x.age = ?1 order by x.lastname desc |
Not |
findByLastnameNot |
… where x.lastname <> ?1 |
In |
findByAgeIn(Collection<Age> ages) |
… where x.age in ?1 |
NotIn |
findByAgeNotIn(Collection<Age> age) |
… where x.age not in ?1 |
True |
findByActiveTrue() |
… where x.active = true |
False |
findByActiveFalse() |
… where x.active = false |
IgnoreCase |
findByFirstnameIgnoreCase |
… where UPPER(x.firstame) = UPPER(?1) |
2. JPA NamedQuery
- 어노테이션으로 쿼리 정의
@Entity
@NamedQuery(
name="Member.findByUsername",
query="select m from Member m where m.username=:username")
public class Member {
}
- XML에 쿼리 정의
<named-query name="Member.findByUsername">
<query><CDATA[
select m
from Member m
where m.username=:username
]></query>
</named-query>
public interface MemberRepository extends JpaRepository<Member, Long> {
List<Member> findByUsername(@Param("username") String username);
// 메소드 이름만으로 Named쿼리 호출, 만약 Named쿼리가 없다면 메소드 이름으로 쿼리 생성 전략 사용
}
3. @Query, 리포지토리 메소드에 쿼리 정의
- 실행할 메소드에 정적 쿼리를 직접 작성하므로 이름 없는 Named 쿼리라 할 수 있다.
- JPA Named 쿼리처럼 애플리케이션 실행 시점에 문법 오류를 발견할 수 있는 장점이 있다.
- 메소드에 JPQL 쿼리 작성
public interface MemberRepository extends JpaRepository<Member, Long> {
@Query("select m from Member m where m.username=?1") //위치기반 파라미터 바인딩
Member findByUsername(String username);
}
- JPA 네이티브 SQL 지원
public interface MemberRepository extends JpaRepository<Member, Long> {
@Query(value="select * from Member where username=:name", nativeQuery=true) //이름기반 파라미터 바인딩
Member findByUsername(@Param("name") String username);
}
4. 페이징과 정렬
- 페이징과 정렬 사용 예제
//count 쿼리 사용
Page<Member> findByName(String name, Pageable pageable);
//count 쿼리 사용 안함
List<Member> findByName(String name, Pageable pageable);
List<Member> findByName(String name, Sort sort);
- Page 사용 예제 실행 코드
List<Member> members = result.getContent(); //조회된 데이터
int totalPages = result.getTotalPages(); //전체 페이지 수
boolean hasNextPage = result.hasNextPage(); //다음 페이지 존재 여부
사용자 정의 리포지토리 구현
public interface MemberRepositoryCustom {
public List<Member> findMemberCustom();
}
public class MemberRepositoryImpl implements MemberRepositoryCustom {
@Override
public List<Member> findMemberCustom() {
//사용자 정의 구현
}
}
public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom {
}
스프링 데이터 JPA와 QueryDSL 통합
- QueryDslPredicateExecutor 사용
- 단점 : join, fetch 사용 불가
- QueryDslRepositorySupport 사용
public class OrderRepositoryImpl extends QueryDslRepositorySupport implements CustomOrderRepository {
public OrderRepositoryImpl() {
super(Order.class);
}
@Override
public List<Order> search(OrderSearch orderSearch) {
QOrder order = QOrder.order;
QMember member = QMember.member;
JPQLQuery query = from(order);
if (StringUtils.hasText(orderSearch.getMemberName())) {
query.leftJoin(order.member, member)
.where(member.name.contains(orderSearch.getMemberName()));
}
if (orderSearch.getOrderStatus() != null) {
query.where(order.status.eq(orderSearch.getOrderStatus()));
}
return query.list(order);
}
}
출처도서 : 자바 ORM 표준 JPA 프로그래밍 - 김영한 지음
'JPA' 카테고리의 다른 글
JPA 도입을 위한 이해 (0) | 2019.12.27 |
---|---|
[개념] JPA 프로그래밍 - 10. 객체지향 쿼리 언어 (0) | 2019.12.27 |
[개념] JPA 프로그래밍 - 07. 고급매핑 (0) | 2019.12.27 |
[개념] JPA 프로그래밍 - 06. 다양한 연관관계 매핑 (0) | 2019.12.27 |
[개념] JPA 프로그래밍 - 05. 연관관계 매핑 기초 (0) | 2019.12.27 |