실전! 스프링 데이터 JPA - 인프런 | 강의
스프링 데이터 JPA는 기존의 한계를 넘어 마치 마법처럼 리포지토리에 구현 클래스 없이 인터페이스만으로 개발을 완료할 수 있습니다. 그리고 반복 개발해온 기본 CRUD 기능도 모두 제공합니다.
www.inflearn.com
순수 JPA 기반 리포지토리 생성
JPA 에서는 변경감지를 통해서 엔티티의 값이 변경 되면, 자동으로 update 쿼리문을 생성해서 DB에 날려주기 때문에, update 쿼리를 생성 할 필요가 없다.
리포지토리 생성
MemberJpaRepositoy
package study.datajpa.repository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import study.datajpa.entity.Member;
import java.util.List;
import java.util.Optional;
@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) {
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();
}
public Member find(Long id) {
return em.find(Member.class, id);
}
}
테스트 코드 추가
리포지토리 테스트를 위해 MemberJpaRepositoryTest에 테스트 메서드 추가
@Test
public void basicCRUD() {
Member member1 = new Member("member1");
Member member2 = new Member("member2");
memberJpaRepository.save(member1);
memberJpaRepository.save(member2);
//단건 조회 검증
Member findMember1 = memberJpaRepository.findById(member1.getId()).get();
Member findMember2 = memberJpaRepository.findById(member2.getId()).get();
assertThat(findMember1).isEqualTo(findMember1);
assertThat(findMember2).isEqualTo(findMember2);
//리스트 조회 검증
List<Member> all = memberJpaRepository.findAll();
assertThat(all.size()).isEqualTo(2);
//카운트 검증
long count = memberJpaRepository.count();
assertThat(count).isEqualTo(2);
//삭제 검증
memberJpaRepository.delete(member1);
memberJpaRepository.delete(member2);
long deletedCount = memberJpaRepository.count();
assertThat(deletedCount).isEqualTo(0);
}
공통 인터페이스 설정
JavaConfig 설정 → 스프링 부트 사용시 생략 가능
@Configuration
@EnableJpaRepositories(basePackages = "study.datajpa.repository")
public class AppConfig {}
- 스프링 부트 사용시
@SpringBootApplication
위치를 지정해준다. - 만약 위치가 달라지면
@EnableJpaRepository
필요
스프링 데이터 JPA가 구현 클래스 대신 생성해준다.
- 스프링 데이터 JPA에서
org.springframework.data.jpa.repository
를 구현한 클래스는 스캔대상이 되어 클래스를 대신 생성 해줌 @Repository
생략 가능 → 컴포넌트 스캔을 스프링 데이터 JPA가 자동으로 처리
적용 해보기
package study.datajpa.repository;
import org.springframework.data.jpa.repository.JpaRepository; //JpaRepository를 구현함으로서 스캔대상이 된다.
import study.datajpa.entity.Team;
public interface TeamRepository extends JpaRepository<Team, Long> {
}
테스트 코드 작성
package study.datajpa.repository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;
import study.datajpa.entity.Member;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
@Transactional
@Rollback(false)
class MemberRepositoryTest {
@Autowired
MemberRepository memberRepository;
@Test
public void testMember() {
Member member = new Member("memberA");
Member savedMember = memberRepository.save(member);
Member findMember = memberRepository.findById(savedMember.getId()).get();
assertThat(findMember.getId()).isEqualTo(member.getId());
assertThat(findMember.getUsername()).isEqualTo(member.getUsername());
assertThat(findMember).isEqualTo(member);
}
@Test
public void basicCRUD() {
Member member1 = new Member("member1");
Member member2 = new Member("member2");
memberRepository.save(member1);
memberRepository.save(member2);
//단건 조회 검증
Member findMember1 = memberRepository.findById(member1.getId()).get();
Member findMember2 = memberRepository.findById(member2.getId()).get();
assertThat(findMember1).isEqualTo(findMember1);
assertThat(findMember2).isEqualTo(findMember2);
//리스트 조회 검증
List<Member> all = memberRepository.findAll();
assertThat(all.size()).isEqualTo(2);
//카운트 검증
long count = memberRepository.count();
assertThat(count).isEqualTo(2);
//삭제 검증
memberRepository.delete(member1);
memberRepository.delete(member2);
long deletedCount = memberRepository.count();
assertThat(deletedCount).isEqualTo(0);
}
}
위의 기본 JPA 테스트 코드와 다를게 없지만, MemberRepository
의 의존을 데이터 JPA로 변경하여 잘 동작하는지만 확인하였다. → 동일한 방식으로 동작
공통 인터페이스 분석
변경점
일부 메서드들은 Jpa 버전이 올라감에 따라 다음과 같이 변경 되었다.
T findOne(ID)
→Optional<T> findById(ID)
boolean exists(ID)
→boolean existsById(ID)
제네릭 타입
T : 엔티티
ID : 엔티티의 식별자 타입
S : 엔티티와 그 자식 타입
주요 메서드
save(S)
: 새로운 엔티티는 저장, 이미 있는 엔티티는 병합delete(T)
: 엔티티 하나를 삭제, 내부에서EntityManager.remove()
호출findById(ID)
: 엔티티 하나를 조회한다. 내부에서EntityManager.find()
호출getOne(ID)
: 엔티티를 프록시로 조회한다. 내부에서EnitityManager.getReference()
호출findAll(…)
: 모든 엔티티를 조회한다. 정렬(Sort)나 페이징(Pageable) 조건을 파라미터로 제공할 수 있다.
정리
이번 장에서는 스프링 데이터 JPA가 제공하는 가장 강력한 기능 중 하나인 JpaRepository
인터페이스에 대해서 다루어 봤다.
사용 방법 : 사용하고자 하는 인터페이스에 JpaRepository<엔티티클래스, PK클래스>를 상속받아서 사용 가능하다.
반응형