Spring Data JPA는 JPA의 상속 인터페이스로 Spring Framework에서 JPA의 사용을 용이하게 하도록 하는 모듈입니다. JPA의 스펙을 사용하면서 그 내부적인 동작을 단순화합니다.
JPA에서는 엔티티와 엔티티 매니저를 통해서 트랜잭션을 관리하고 CRUD 메서드를 수행해야합니다. 하지만 이러한 동작을 Repository에 정의하여 개발자가 직접 엔티티 매니저를 제어하지 않아도 됩니다.
또한 매니저를 제어하기 위한 DAO 클래스의 구현체를 작성하지 않아도 되는 장점이 있습니다.
SimpleJpaRepository
클래스는 JpaRepository
의 구현체로 내부적으로 EntityManager
를 통한 JPA 동작을 수행한다는 것을 알 수 있습니다.
JPA를 상속한 JpaRepository
인터페이스를 제공하며 해당 인터페이스를 상속 혹은 구현하는 것 만으로 기본 CRUD 메서드가 제공됩니다.
JpaRepository
를 상속/구현한 클래스를 Spring Data에서 감지하여 구현체를 만들어 Bean
에 등록합니다. 이는 JpaRepository
내에 @Repository
어노테이션이 존재하기 때문입니다.
public interface MemberRepository extends JpaRepository<Member, Long>{
}
위 코드를 작성하여 CRUD 기능을 사용할 수 있습니다. 이 때 제네릭 타입은 엔티티 클래스와 엔티티 클래스의 PK
타입이 입력되어야합니다.
JpaRepository
에서 CRUD를 수행하기 위한 기본 메서드가 제공됩니다. 이는 JpaRepository
가 상속하는 CrudRepository
에 작성되어 있습니다.
/*
* Entity 타입, PK(식별자) 타입을 제네릭으로 선언
* 각 아규먼트가 null 일경우 IllegalArgumentException을 던짐
*/
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
/**
엔티티 객체 혹은 자식객체를 영속(INSERT)하고 해당 엔티티 반환
*/
<S extends T> S save(S entity);
/**
엔티티 타입의 이터러블( ex) Collection) 을 모두 영속하고 엔티티 이터러블 반환
*/
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
/**
식별자로 영속객체를 찾아서 Optional에 담아 엔티티 반환
찾지 못했을 경우 비어있는 Optional 반환
*/
Optional<T> findById(ID id);
/**
해당 PK를 갖고 있는 엔티티의 존재 여부 반환
*/
boolean existsById(ID id);
/**
영속상태의 모든 엔티티 반환
*/
Iterable<T> findAll();
/**
식별자들을 포함한 이터러블을 매개로 엔티티 이터러블을 반환
*/
Iterable<T> findAllById(Iterable<ID> ids);
/**
등록된 엔티티 수 반환
*/
long count();
/**
해당 식별자 엔티티를 영속에서 제거
*/
void deleteById(ID id);
/**
해당 엔티티를 영속에서 제거
*/
void delete(T entity);
/**
엔티티 이터러블 내 모든 엔티티를 제거
*/
void deleteAll(Iterable<? extends T> entities);
/**
모든 엔티티 제거
*/
void deleteAll();
}
위와 같이 기본적으로 구현되는 쿼리 메서드를 사용할 수도 있지만 인터페이스 내에 메서드 네임 규칙을 따르는 메서드를 만들면 구현체 없이 CRUD 쿼리를 만들 수 있습니다.
public interface MemberRepository extends JpaRepository<Member, Long>{
Optional<Member> findByEmailAndName(String email, String name);
}
Spring Data Jpa 공식문서에서 메서드 명 규칙을 확인할 수 있습니다.
위와 같이 메서드 명명 규칙을 이용해서 쿼리 메서드를 JPA가 생성하도록할 수도 있지만 @Query
어노테이션으로 수동 쿼리를 입력해줄 수 있습니다.
이때 쿼리문에 작성하는 쿼리는 JPQL 로 SQL을 작성하기 위해서는 nativeQuery = true
옵션을 사용해야합니다.
간단하게 JPQL로 쿼리문을 작성하는 법을 알아보겠습니다. 기본적인 문법은 SQL과 같습니다.
?1
@Query("SELECT Member FROM member where name = ?1"
@Param
어노테이션을 작성하여 :param
과 같은 형태로 매핑@Query("SELECT Member FROM member where name = :name"
public interface MemberRepository extends JpaRepository<Member, Long>{
@Query("SELECT Member FROM member where name = :name")
Optional<Member> findByName(@Param("name") String name);
}
#{#enitityName}
public interface MemberRepository extends JpaRepository<Member, Long>{
@Query("SELECT #{#entityName} FROM member where name = :name")
Optional<Member> findByName(@Param("name") String name);
}
Reference
https://goodgid.github.io/Spring-Data-JPA-Query_Part_2/
https://docs.spring.io/spring-data/jpa/docs/1.4.1.RELEASE/reference/html/jpa.repositories.html
https://www.baeldung.com/the-persistence-layer-with-spring-data-jpa