Spring Data는 인터페이스만 선언하면 구현체를 런타임에 만들어 주는 영속성 추상화(persistence abstraction)다. JpaRepository<엔티티, ID타입>을 상속하면 저장·조회·삭제·페이징이 바로 생기고, 메서드 이름 규칙만으로 쿼리를 만들 수도 있다.
인터페이스 계층
Repository: 메서드가 없는 표시용(marker) 인터페이스CrudRepository:save,findById,findAll,delete등 기본 CRUD(Create, Read, Update, Delete)PagingAndSortingRepository: 정렬·페이징JpaRepository: 위를 모두 포함하고flush, 배치 삭제 같은 JPA 기능을 더한다
필요한 만큼만 고를 수 있게 나뉜 구조라 인터페이스 분리 원칙(Interface Segregation Principle, ISP)의 예로 자주 든다.
쿼리 메서드
public interface ContactRepository extends JpaRepository<Contact, Long> {
List<Contact> findByStatus(String status);
List<Contact> findByStatusAndCreatedAtAfterOrderByCreatedAtDesc(String status, LocalDateTime after);
Optional<Contact> findFirstByEmailIgnoreCase(String email);
long countByStatus(String status);
boolean existsByEmail(String email);
Page<Contact> findByStatus(String status, Pageable pageable);
}- 이름은
By를 기준으로 앞은 동작(find·read·query·count·exists·delete), 뒤는 조건이다. 조건은And·Or로 잇고GreaterThan,Like,In,IsNull,OrderBy같은 키워드를 붙인다 - 앱이 시작할 때 이름을 파싱하므로 필드명 오타는 시작 시점에 실패한다
- 조건이 셋을 넘어 이름이 길어지면 @Query로 직접 쓴다
Pageable을 받으면 페이지네이션이 된다(페이지네이션 (offset·cursor))
알아 둘 점
save()는 새 엔티티면 persist, 아니면 merge한다. 영속 상태의 엔티티는save없이도 트랜잭션 커밋 때 바뀐 값이 반영된다(더티 체킹)- 실행되는 SQL은
spring.jpa.show-sql=true또는logging.level.org.hibernate.SQL=DEBUG로 본다(로그 레벨과 Logback) - 연관 엔티티를 목록에서 건드리면 N+1 문제이 생기기 쉽다.
@EntityGraph나 fetch join으로 함께 가져온다 - 생성·수정 시각 자동 기록은 JPA Auditing
SQL을 직접 쓰는 아래층은 JDBC와 JdbcTemplate, 엔티티가 관리되는 원리는 영속성 컨텍스트를 본다.
출처: Spring Data JPA 문서: Core concepts · Query Creation · Paging and Sorting