공통 인터페이스 설정
JavaConfig 설정- 스프링 부트 사용 시 생략 가능
@Configuration
@EnableJpaRepositories(basePackages = "jpabook.jpashop.repository")
public class AppConfig {}
- 스프링 부트 사용시 @SpringBootApplication 위치를 지정(해당 패키지와 하위 패키지 인식)
- 만약 위치가 달라지면@EnableJpaRepositories 필요
public interface MemberRepository extends JpaRepository<Member, Long> {
}
@SpringBootTest
@Transactional
class MemberJpaRepositoryTest {
@Autowired
MemberJpaRepository memberJpaRepository;
...
}
인터페이스밖에 없는데 어떻게 memberJpaRepository를 사용할 수 있을까
그 이유는 스프링 데이터 JPA가 스프링 데이터 JPA와 관련된 인터페이스를 가지고 있으면 구현 클래스를 대신 생성해서 memberJpaRepository에 주입하기 때문이다.
- org.springframework.data.repository.Repository를 구현한 클래스는 스캔 대상이 된다.
- MemberRepository 인터페이스가 동작한 이유
- 스프링 데이터 JPA가 proxy 기술로 가짜 클래스를 만든 다음에 주입 해준다.
- 그래서 System.out.println(memberRepository.getClass())같이 출력 해보면 프록시 객체임을 알 수 있다.
- memberRepository.getClass() -> class com.sun.proxy.$ProxyXXX
- @Repository 애노테이션 생략 가능
- @Repository는 컴포넌트 스캔과 JPA의 예외를 스프링 예외로 변환하는 기능을 가지고 있다.
- 스프링 데이터 JPA는 그 두가지 기능을 자동으로 처리해줘서 @Repository 생략이 가능하다.
- 컴포넌트 스캔을 스프링 데이터 JPA가 자동으로 처리
- JPA 예외를 스프링 예외로 변환하는 과정도 자동으로 처리
공통 인터페이스 분석
- JpaRepository 인터페이스: 공통 CRUD 제공
- 제네릭은 <엔티티 타입, 식별자 타입> 설정
JpaRepository 코드 내부를 들어가 보자.
JpaRepository 공통 기능 인터페이스
package org.springframework.data.jpa.repository;
@NoRepositoryBean
public interface JpaRepository<T, ID> extends ListCrudRepository<T, ID>, ListPagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
/**
* Flushes all pending changes to the database.
*/
void flush();
/**
* Saves an entity and flushes changes instantly.
*
* @param entity entity to be saved. Must not be {@literal null}.
* @return the saved entity
*/
<S extends T> S saveAndFlush(S entity);
...
}
JpaRepository를 사용하는 인터페이스
public interface MemberRepository extends JpaRepository<Member, Long> {
}
공통 인터페이스 구성

스프링 데이터 프로젝트라는 공통 프로젝트가 존재한다.
공통 프로젝트는 JPA든 Mongo든 Redis든 공통적으로 사용할 수 있다.
위 이미지에서 스프링 데이터 부분은 Spring Data Commons라는 Spring Data의 공통부분이다.
그래서 이러한 공통 기능을 제공하는 인터페이스들에 대해 알아보자.
PagingAndSortingRepository
package org.springframework.data.repository;
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends Repository<T, ID> {
/**
* Returns all entities sorted by the given options.
*
* @param sort the {@link Sort} specification to sort the results by, can be {@link Sort#unsorted()}, must not be
* {@literal null}.
* @return all entities sorted by the given options
*/
Iterable<T> findAll(Sort sort);
/**
* Returns a {@link Page} of entities meeting the paging restriction provided in the {@link Pageable} object.
*
* @param pageable the pageable to request a paged result, can be {@link Pageable#unpaged()}, must not be
* {@literal null}.
* @return a page of entities
*/
Page<T> findAll(Pageable pageable);
}
페이징과 Sorting은 RDBM이나 NoSQL이나 비슷하다.
그래서 페이징과 Sorting에 대해서 공통 인터페이스가 제공된다.
그 말은 나중에 스프링 데이터 Mongo 이런 걸로 바꿔도 아래 인터페이스의 기능을 그대로 쓸 수 있다.
CrudRepository
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
/**
* Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
* entity instance completely.
*
* @param entity must not be {@literal null}.
* @return the saved entity; will never be {@literal null}.
* @throws IllegalArgumentException in case the given {@literal entity} is {@literal null}.
* @throws OptimisticLockingFailureException when the entity uses optimistic locking and has a version attribute with
* a different value from that found in the persistence store. Also thrown if the entity is assumed to be
* present but does not exist in the database.
*/
<S extends T> S save(S entity);
...
/**
* Retrieves an entity by its id.
*
* @param id must not be {@literal null}.
* @return the entity with the given id or {@literal Optional#empty()} if none found.
* @throws IllegalArgumentException if {@literal id} is {@literal null}.
*/
Optional<T> findById(ID id);
...
}
스프링 데이터 프로젝트는 기본적으로 공통의 CRUD 기능도 제공한다.
Repository
/**
* Central repository marker interface. Captures the domain type to manage as well as the domain type's id type. General
* purpose is to hold type information as well as being able to discover interfaces that extend this one during
* classpath scanning for easy Spring bean creation.
* <p>
* Domain repositories extending this interface can selectively expose CRUD methods by simply declaring methods of the
* same signature as those declared in {@link CrudRepository}.
*
* @see CrudRepository
* @param <T> the domain type the repository manages
* @param <ID> the type of the id of the entity the repository manages
* @author Oliver Gierke
*/
@Indexed
public interface Repository<T, ID> {
}
최상위에는 Repository 인터페이스가 있다.
마커 인터페이스라고 하는데 기능이 있는 거는 아니고 스프링 데이터가 제공하는 Repository다.
classpath scanning for easy Spring bean creation. 주석중에 이와 같은 내용이 있는데 해석해 보면 Spring bean을 만들 때 클래스 패스 스캔을 하기 쉽게 만들어주는 기능을 제공한다는 소리다.
근데 이 공통의 기능 말고 각 DB마다 특화된 기능이 존재한다.
Spring Data JpaRepository 인터페이스는 JPA에 특화된 기능들만 제공한다.
Spring Data Mongo는 Mongo와 같은 NoSQL에 특화된 기능들을 제공한다.
주의
T findOne(ID) 과거에 제공 -> Optional<T> findById(ID)로 변경
제네릭 타입
- T : 엔티티
- ID : 엔티티의 식별자 타입
- S : 엔티티와 그 자식 타입
주요 메서드
- save(S) : 새로운 엔티티는 저장하고 이미 있는 엔티티는 병합한다.
- delete(T) : 엔티티 하나를 삭제한다. 내부에서 `EntityManager.remove()` 호출
- findById(ID) : 엔티티 하나를 조회한다. 내부에서 `EntityManager.find()` 호출
- getOne(ID) : 엔티티를 프록시로 조회한다. 내부에서 `EntityManager.getReference()` 호출
- findAll(...) : 모든 엔티티를 조회한다. 정렬( `Sort` )이나 페이징( `Pageable` ) 조건을 파라미터로 제공할 수 있다.
참고: JpaRepository는 대부분의 공통 메서드를 제공한다.
'JPA > Spring Data Jpa' 카테고리의 다른 글
나머지 기능들 (0) | 2024.08.27 |
---|---|
스프링 데이터 JPA 분석 (0) | 2024.08.27 |
확장 기능 (0) | 2024.08.26 |
쿼리 메소드 기능 (0) | 2024.08.26 |