순수 JPA 기반 리포지토리 만들기
JPA는 Java 개발자가 관계형 데이터베이스에서 자바 객체를 저장, 수정, 삭제, 조회할 수 있게 도와주는 인터페이스이다.
리포지토리는 기본적으로 CRUD(Create, Read, Update, Delete)를 수행할 수 있어야 한다.
우선 공통 인터페이스를 적용하기 전에 순수 JPA기반 리포지토리 기반으로 api를 만들어 보겠다.
@Repository
public class MemberJpaRepository {
@PersistenceContext
private EntityManager em;
// 저장
public Member save(Member member) {
em.persist(member);
return member;
}
// 삭제
public void delete(Member member) {
em.remove(member);
}
// 전체 조회
public List<Member> findAll() {
return em.createQuery("select m from Member m", Member.class).getResultList();
}
// 단건 조회
public Optional<Member> findById(Long id) { // Optional : return 값이 null일 수도 있고 아닐 수도 있다.
Member member = em.find(Member.class, id);
return Optional.ofNullable(member);
}
// 카운트
public long count() {
return em.createQuery("select count(m) from Member m", Long.class).getSingleResult();
}
}
변경(수정)같은 경우에 JPA는 변경 감지(Dirty Checking) 기능을 제공한다. 트랜젝션 안에서 엔티티를 조회한 후 데이터를 변경하면, 트랜잭션이 종료되는 시점에 변경 감지 기능이 작동한다. 변경된 엔티티를 감지하고 UPDATE SQL을 자동으로 실행한다.
공통 인터페이스 설정
JavaConfig 설정을 해야 스프링부트를 사용할 수 있다. 단, 스프링부트를 사용한다면 설정하지 않아도 된다.
이는 @SpringBootApplication 애노테이션 위치를 기준으로 해당 패키지와 하위 패키지들을 자동으로 스캔하므로, 따로 위치를 지정하지 않아도 된다. 만약, 위치가 달라진다면 @EnableJpaRepositories를 추가해야 한다.
스프링 데이터 JPA가 구현 클래스를 대신 생성한다
org.springframework.data.repository.Repository 리포지토리를 구현한 클래스를 자동으로 스캔하고 등록한다.
예를 들어, MemberRepository 인터페이스는 구현 클래스 없이도 잘 동작하며 인터페이서의 구체적인 클래스를 확인해보면, com.sun.proxy.&ProxyXXX와 같은 프록시 클래스라는 것을 확인할 수 있다.
public interface MemberRepository extends JpaRepository<Member, Long> { }
System.out.println("memberRepository = " + memberRepository.getClass()); // memberRepository = class jdk.proxy2.$Proxy130
그리고 @Repository 어노테이션을 생략할 수 있다. 이는 스프링 데이터 JPA가 컴포넌트 스캔을 자동으로 처리하고, JPA 예외를 스프링 예외로 변환하는 과정도 자동으로 처리하기 때문이다.
공통 인터페이스 적용
이전에 순수 JPA로 구현했던 MemberJpaRepository를 스프링 데이터 JPA 기반의 MemberRepository로 대체하겠다.
public interface MemberRepository extends JpaRepository<Member, Long> {}
MemberRepository는 JpaRepository<엔티티 타입, 식별자 타입(ID)>을 상속받고 있다. 이를 사용하면 위의 MemberJpaRepository처럼 각 CRUD 기능을 직접 구현할 필요 없이 간편하게 사용할 수 있다.
공통 인터페이스 분석
JpaRepository 인터페이스는 공통 CRUD를 제공하며, 제네릭은 <엔티티 타입, 식별자 타입> 설정을 한다.
JpaRepository는 대부분의 공통 메서드를 제공한다.
/** JpaRepository 공통 기능 인터페이스 */
public interface JpaRepository<T, ID extends Serializable>
extends PagingAndSortingRepository<T, ID> {
}
/** JpaRepository를 사용하는 인터페이스 */
public interface MemberRepository extends JpaRepository<Member, Long> {}
중요 변경 사항(이전 것 사용 불가)
- T findOne(ID) → Optional<T> findById(ID) 로 변경됨
- boolean exists(ID) → boolean existById(ID) 로 변경됨
제네릭 타입
- T : 엔티티
- ID : 엔티티의 식별자 타입
- S : 엔티티와 그 자식 타입
주요 메서드
- save(S) : 새로운 엔티티는 저장하고, 이미 있는 엔티티는 병합한다.
- delete(T) : 엔티티 하나를 삭제한다. 내부에서 EntityManager.remove() 가 호출된다.
- findById(ID) : 엔티티 하나를 조회한다. 내부에서 EntityManager.find() 가 호출된다.
- getOne(ID) : 엔티티를 프록시로 조회한다. 내부에서 EntityManager.getReference() 가 호출된다.
- findAll(...) : 모든 엔티티를 조회한다. 정렬(Sort)이나 페이징(Pageable) 조건을 파라미터로 제공할 수 있다.
[출처]
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-JPA-%EC%8B%A4%EC%A0%84 → 이 글은 김영한님의 "실전! 스프링 데이터 JPA" 강의 중 1~4장을 듣고 정리한 내용입니다.
'Spring > 자바 ORM 표준 JPA 프로그래밍' 카테고리의 다른 글
[Spring Data JPA] 2-2. JPA 페이징과 정렬 (0) | 2024.08.30 |
---|---|
[Spring Data JPA] 2-1. 쿼리 메소드 기능 (0) | 2024.08.30 |
[JPA 활용 2] 4. OSIV와 성능 최적화 (0) | 2024.08.17 |
[JPA 활용 2] 3. API 개발 고급 - 컬렉션 조회 최적화 (0) | 2024.08.17 |
[JPA 활용 2] 2. API 개발 고급 - 지연 로딩과 조회 성능 최적화 (0) | 2024.08.15 |