Spring
SpringData 구조 밑 JPA repositoey 원리
sehunbang
2024. 3. 5. 16:49
SpringData 구조

SpringData 기능 목록
- 강력한 리포지토리 및 사용자 지정 객체 매핑 추상화
- 리포지토리 메서드 이름에서 동적 쿼리 파생
- 기본 속성을 제공하는 구현 도메인 기본 클래스
- 명료한 추적기능 지원(생성일시, 마지막 변경일시, 생성자, 마지막 변경자)
- 사용자 지정 리포지토리 코드 통합 가능성
- JavaConfig 및 사용자 지정 XML 네임스페이스를 통한 간편한 Spring 통합
- Spring MVC 컨트롤러와의 고급 통합
- 교차 스토어 지속성에 대한 실험적 지원
SpringData Jpa 와 JpaRepository 원리

기존 Repository vs 새로운 JpaRepository
- 기존 Repository
- **@Repository** 을 클래스에 붙인다.
- 앞서배운 RawJPA의 Repository 기능만 가진 구현체가 생성된다. (DB별 예외처리 등)
- 새로운 JpaRepository
- JpaRepository<Entity,ID> 인터페이스를 인터페이스에 extends 붙인다.
- @NotRepositoryBean 된 ****상위 인터페이스들의 기능을 포함한 구현체가 프로그래밍된다. (@NotRepositoryBean = 빈생성 막음)
- SpringDataJpa 에 의해 엔티티의 CRUD, 페이징, 정렬 기능 메소드들을 가진 빈이 등록된다. (상위 인터페이스들의 기능)
- JpaRepository<Entity,ID> 인터페이스를 인터페이스에 extends 붙인다.
Repository 기능을 제한하기!
🚧 JpaRepository 실무 꿀팁!!!
- JpaRepository 에서 사용할 메소드 제한하기
- JpaRepository 는 기본적으로 모든 기능을 제공하기 때문에 리스크가 있을 수 있다.
- 따라서, 아래와 같은 방법으로 원하는 기능 메소드만 구현하도록 제한할 수 있다.
@RepositoryDefinition 을 인터페이스에 붙이는법 (가장 많이 쓰임)
- 어노테이션을 붙이면 BeanDefinition 에 직접 접근하여 프로그래밍으로 주입받을 구현체 메소드들을 지정해서 요청할 수 있다.
@RepositoryDefinition(domainClass = Comment.class, idClass = Long.class)
public interface CommentRepository {
Comment save(Comment comment);
List<Comment> findAll();
}
@NoRepositoryBean 인터페이스로 한번더 감싸는법
상위 인터페이스 개념을 하나 더 만들어서 열어줄 메소드만 선언해준다.
@NoRepositoryBean
public interface MyRepository<T, ID extends Serializable> extends Repository<T, ID> {
<E extends T> E save(E entity);
List<T> findAll();
}
Repository 에 기능 추가하기!
delete() 메소드의 내부 기능 확인하기.
1. delete 호출시 영속성 상태인지 확인한다.
- 영속성 컨텍스트에 없다면(!em.contains(entity)) 엔티티를 조회해서 영속성 상태로 바꾼다.
- 💁♂️어차피 삭제할껀데 굳이?!?!
- Cascade, orphanRemoval 에 의한 자식도 삭제가 누락되지 않도록!!!
- JpaRepository 의 delete() 는 해당 엔티티를 바로 삭제하지 않는다.
- remove() 메소드를 통해 remove 상태로 바꾼다.
1. 우선, 우리가 기능을 추가할 빈 Repository 인터페이스를 만들자
public interface MyRepository {
void delete(User user);
User find(Long l);
}
2. delete 쿼리가 바로 날아가도록 기능을 개선해보자
@Repository
@Transactional
public class MyRepositoryImpl implements MyRepository {
@Autowired
EntityManager entityManager;
@Override
public void delete(User user) {
entityManager.remove(user);
}
@Override
public User find(Long l) {
return entityManager.find(User.class,l);
}
}
3. findAll 할때 (이름만) 가져오도록 기능을 추가해보자
public interface MyRepository {
void delete(User user);
User find(Long l);
List<String> findAll();
}
@Repository
@Transactional
public class MyRepositoryImpl implements MyRepository {
@Autowired
EntityManager entityManager;
@Override
public void delete(User user) {
entityManager.remove(user);
}
@Override
public User find(Long l) {
return entityManager.find(User.class,l);
}
@Override
public List<String> findAll() {
return entityManager.createQuery("SELECT u.username FROM User AS u", String.class).getResultList();
}
}