메소드를 호출하여 데이터를 검색 할 수 있도록
미리 검색 메소드를 정의해두는 인터페이스
Entity 에 있는 데이터를 조회/저장/변경/삭제(CRUD) 하기 위해,
Spring JPA 에서 Repository 를 정의하므로 해당 Entity 에 있는 데이터를 사용할 수 있다.
→ 즉, CRUD 처리를 위한 공통 인터페이스를 제공
Repository
내부적으로 EntityManager 가 직접 대상 Entity의 데이터를 관리하므로,
굳이 Repository 인터페이스를 정의하지 않고도
직접 EntityManger 를 사용해 Persistance Layer 를 구현 할 수 있다.그러나,
Spring JPA 에서 Repository 의 내부 구현체를 자동 생성하므로,
별도의 구현체를 따로 생성하지 않아도 된다.
org.springframework.data.jpa.repository 패키지의 JpaRepository 인터페이스를 상속하여 만들어진다.
exteds JpaRepository <엔티티 클래스이름 , ID 필드 타입> 을 지정한다.
기본형의 경우, Wrapper 클래스를 지정한다.
클래스의 선언 앞에 @Repository 을 붙혀놓아야지 jpa 임을 나타낸다.
스프링 공식 문서를 참고하면, 더 많은 쿼리와 키워드를 찾을 수 있다.
참고: Spring Data JPA - Reference Documentation - 5.3. Query methods
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
@Getter @NoArgsConstructor @Entity
public class Comment extends BaseTimeEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String comment;
@Column(nullable = false)
private Long postId;
public Comment(CommentDto commentDto){
this.comment = commentDto.getComment();
this.postId = commentDto.getPost_id();
}
public void update(CommentDto commentDto){
this.comment = commentDto.getComment();
}
}
public interface CommentRepository extends JpaRepository<Comment, Long> {
List<Comment> findAllByPostId(Long post_id);
}
@GetMapping("/api/comment/{id}")
public List<Comment> listComment(@PathVariable Long id){
return commentRepository.findAllByPostId(id);
}
Repository 에서 정의한 메소드 : findAllByPostId()
특히, save( ), delete( ) 는 DB 에 직접적인 관여를 하기 떄문에 중요하다.
메소드 이름을 붙이는 것만으로도, 메소드가 자동 생성된다.
findBy + 엔티티의 속성 이름 : 쿼리를 요청하는 메서드 임을 알림
countBy + 엔티티의 속성 이름 : 쿼리 결과 레코드 수를 요청하는 메서드 임을 알림
findById
findByName
findByAddress
findByMail
findByNameLike(String name) : name에서 인수의 텍스트를 포함하는 엔티티를 검색 (퍼지 검색)
findByNameNotLike(String name) : name에서 인수의 텍스트를 포함하지 않는 엔티티를 검색 (퍼지 검색)
퍼지검색
- 입력된 검색 키워드가 정확하지 않아도, 사용자의 요구를 예상하고 적절한 단어를 찾는 검색 방식
- 표기의 흔들림, 유의어/동의어를 보완
- 맞춤법 교정은 사용자의 입력 실수를 지적하고 보다 정확도 높은 검색을 제공
findByNameStartingWith("A") : ame의 값이 "A"로 시작하는 항목을 검색
findByNameIsNull() : name의 값이 null인 것만 검색
findByNameIsNotNull()
findByCheckTrue() : check라는 항목이 true인 것만을 검색
findByCreateBefore(new Date()) : create라는 항목의 값이 현재보다 이전의 것만을 찾는다. (reate가 Date인 경우)
findByAgeLessThan(int age) : 그 항목의 값이 인수보다 작은 것을 검색
findByAgeGreaterThan(int age) : 그 항목의 값이 인수보다 큰 것을 검색
findByAgeGraterThanEqual(int age) : 그 항목의 값이 인수보다 크거나 같은 것을 검색
findByAgeLessThan(20) : age의 값이 20보다 작은 것을 찾는다.
findByEmailAndUserId(String email, String userId)
findByEmailOrUserId(String email, String userId)
findByCreatedAtBetween(Date fromDate, Date toDate)
findByAgeBetween(10, 20) : age의 값이 10이상 20이하인 것을 검색
findByJob(String … jobs)
findByEmailOrderByNameAsc(String email)
jpa 에 정의된 키워드를 조합하면, 특정 조건에 해당하는 데이터를 원하는 형태대로 가져올 수 있다.
그러나,
이런 경우에는 직접 쿼리를 작성할 수 있는 방법을 제공한다.
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
}
@Query 中 nativeQuery 속성을 true로 설정하지 않으면, Default값으로 JPQL 문법이 동작한다.
JPQL 문법
- JPA에서 사용 되는 언어
- 쿼리 구문과 유사하나,
Table 이 아닌Entity 를 기준으로 데이터를 조회- nativeQuery 속성을 통해, 직접 쿼리를 작성할 수도 있다.
@Entity
@NamedQuery(
name = "Member.findByUsername",
query = "select m from Member m where m.username = :username")
public class Member {
...
}
쿼리 호출
1) 방법 : JPA를 직접 사용해서 Named 쿼리 호출
public class MemberRepository {
public List<Member> findByUsername(String username) {
...
List<Member> resultList =
em.createNamedQuery("Member.findByUsername", Member.class)
.setParameter("username", "회원1")
.getResultList();
}
}
2) 방법 : 스프링 데이터 JPA로 Named 쿼리 호출
// Member : 도메인 클래스
// findByUsername : 메소드 이름
public interface MemberRepository extends JpaRepository<Member, Long> {
List<Member> findByUsername(@Param("username") String username);
}
public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
// ...
}
// 제네릭에 회원 엔티티와 식별자 타입을 지정
public interface MemberRepository extends JpaRepository<Member, Long> {
Member findByUsername(String username);
// select m from Member m where username = :username
}
(공통 인터페이스의 구성)
Member findByEmail(String email);
List<Member> findByName(String name);
스프링 데이터 JPA는 쿼리 메소드에 페이징과 정렬 기능 제공
파라미터에 Pageable 사용하면,
반환 타입으로 List 나 org.springframework.data.domain.Pageable 사용 가능
// count 쿼리 사용
// Page 반환 타입을 사용하면, 스프링 데이터 JPA 는 페이징 기능을 제공하기 위해 검색된 전체 데이터 건수를 조회하는 count 쿼리를 추가로 호출
Page<Member> findByName(String name, Pageable Pageable);
// count 쿼리 사용 X
List<Mamber> findByName(String name, Pageable Pageable);
List<Mamber> findByName(String name, Sort sort);
@RestController
@RequestMapping("/member")
public class MemberController {
>
@Autowired
MemberService memberService;
>
@RequestMapping("")
// Query 메소드의 입력변수로 Pageable 변수를 추가하면, Page 타입을 반환형으로 사용 가능
// Pageable 객체를 통해 페이징과 정렬을 위한 파라미터를 전달
Page<Member> getMembers(Pageable pageable){
return memberService.getList(pageable)
}
}
GET /users?page=1&size=10&sort=createdAt,desc&sort=userId,asc
정렬과 페이지 정보를 접속 URI 에서부터 Repository 까지 바로 전달이 가능
public interface Page<T> extends Iterable<T> {
int getNumber(); // 현재 페이지
int getSize(); // 페이지 크기
int getTotalPages(); // 전체 페이지 수
int getNumberOfElements(); // 현재 페이지에 나올 데이터 수
long getTotalElements(); // 전체 데이터 수
boolean hasPreviousPage(); // 이전 페이지 여부
boolean isFirstPage(); // 현재 페이지가 첫 페이지 인지 여부
boolean hasNextPage(); // 다음 페이지 여부
boolean isLastPage(); // 현재 페이지가 마지막 페이지 인지 여부
Pageable nextPageable(); // 다음 페이지 객체, 없으면 null
Pageable previousPageable();// 이전 페이지 객체, 없으면 null
List<T> getContent(); // 조회된 데이터
boolean hasContent(); // 조회된 데이터 존재 여부
Sort getSort(); // 정렬 정보
}
public interface MemberRepository extends Repository<Member, Long> {
Page<Member> findByNameStartingWith(String name, Pageable Pageable);
}
// 페이징 조건과 정렬 조건 설정
PageRequest pageRequest =
new PageRequest(0, 10, new Sort(Direction.DESC, "name"));
Page<Member> result =
memberRepository.findByNameStartingWith("김", pageRequest);
List<Member> members = result.getContent(); // 조회된 데이터
int totalPages = result.getTotalPages(); // 전체 페이지 수
boolean hasNextPage = result.hasNextPage(); // 다음 페이지 존재 여부
참고: JPA Repository를 사용하는 이유
참고: JpaRepository Query 작성
참고: [Spring] Spring Data JPA 기본 사용법 ( JpaRepository )
참고: JPA 사용법 (JpaRepository)
참고: [Spring + JPA] Spring Data JPA 란? (1)
참고: 공통 인터페이스 기능