어느 엔티티든 공통으로 사용하는 기능이 있다. save나 find 등등
이러한 기능을 공통으로 생산해주면 좋겠다는 취지의 오픈소스 프로젝트가 발전해서
spring-data-jpa 프로젝트가 됐다.
공통 CRUD 지원
save, find같은 어느 엔티티나 공통적으로 쓸만한 기능이 전부 들어있다.
기본적으로 @Transactional(readOnly = true)가 달려있고
변경성 쿼리는 @Transactional이 달려있다.
메소드 명 쿼리화
쿼리 메소드 기능을 지원해줘서 짧은 쿼리문은 메소드명으로 알아서 변환해준다.
해당 메소드 명에 사용된 필드가 변경되면 애플리케이션 시작 시점에 오류를 발생시킨다.
@Query
인터페이스 메소드에 @Query를 달아서 실행되는 쿼리를 바로 지정할 수 있다.
해당 쿼리문은 필드 명이 변경되면 애플리케이션 시작 시점에 오류가 발생한다.
페이징
Pageable을 파라미터로 주면 사용할 수 있다.
Spring data는 페이징을 표준화해서 db에 국한되지 않고 사용할 수 있다.
페이징 <---> 슬라이스로 타입만 바꾸면 변환할 수 있어서 생산성이 좋다.
@Qeury에 countQuery로 가져올 개수를 지정할 수 있다.
패치조인
@EntityGraph의 attributePaths를 지정해주면 패치 조인 쿼리를 추가해준다.
사용자 정의 리포지토리
사용자 정의 리포지토리 인터페이스를 상속받으면
Spring data jpa가 사용자 정의 인터페이스의 메소드를 확장해서 사용하게 해준다.
Auditing
어플리케이션에 @EnableJpaAuditing을 달아주고 기존 JPA Auditing 클래스에
@EntityLister(AuditingEntityListener.class)을 달아주고
필드에 @CreatedDate, @ModifiedDate 등을 달아주면 쉽게 지원해준다.
벌크성 메소드
벌크성으로 update하는 메소드에는 ExcuteUpdate를 위해 @Modifying을 넣어줘야한다.
또한, 영속성 컨텍스트를 비우기 위해 Modifying에 clearAutomatically를 true로 해줘야한다.
사용자 정의 리포지토리
사용자 정의 리포지토리를 사용할 때는 Spring data jpa 인터페이스 이름에 Impl을 붙인 클래스를 사용하는 것이 관례다.(설정을 바꾸지 않는 이상 클래스를 못 찾는다)
save()
새로운 엔티티면 persist, 새로운 엔티티가 아니면 merge를 한다.
엔티티를 구분하는 방법은 디폴트로 식별자가 객체라면 null, 자바 기본 타입이라면 0으로 판단한다.(@GeneratedValue pk가 persist하기 전까지 값이 생기지 않기 때문)
엔티티의 PK를 임의의 값으로 세팅해서 insert하고 싶다해도 persist가 되지 않고 merge를 실행시키고 select -> update or insert로 작동해서 비효율적이다.
이럴 때는 엔티티에 Persistable 인터페이스를 상속 받아 엔티티를 구분하는 방법을 직접 설정해야한다.
ex)@CreatedDate로 판단하는 등