[스프링 데이터 JPA] 3. 공통 인터페이스 기능

2024. 1. 24. 01:12·인프런 Spring 강의 정리/실전! 스프링 데이터 JPA
728x90
반응형

📌 순수 JPA 기반 리포지토리 만들기

✔ 기본 CRUD

  • 저장
  • 변경 -> 변경감지 사용
    • 트랜잭션 안에서 엔티티를 조회한 다음에 데이터를 변경하면, 트랜잭션 종료 시점에 변경 감지 기능이 작동해서 변경된 엔티티를 감지하고 UPDATE SQL 실행
  • 삭제
  • 전체 조회
  • 단건 조회
  • 카운트

 

회원

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);
    }
}

 

 

팀

package study.datajpa.repository;

import jakarta.persistence.Entity;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import study.datajpa.entity.Team;

import java.util.List;
import java.util.Optional;

@Repository
public class TeamJpaRepository {

    @PersistenceContext
    private EntityManager em;

    public Team save(Team team){
        em.persist(team);
        return team;

    }

    public void delete(Team team){
        em.remove(team);
    }
    public List<Team> findAll(){
        return em.createQuery("select t from Team t", Team.class).getResultList();
    }

    public Optional<Team> findById(Long id){
        Team team = em.find(Team.class, id);
        return Optional.ofNullable(team);
    }

    public long count(){
        return em.createQuery("select count(t) from Team t", Long.class).getSingleResult();
    }
}

➡ 회원 리포지토리와 거의 동일

 

 

 

📌순수 JPA 기반 리포지토리 테스트

회원

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
class MemberJpaRepositoryTest {

    @Autowired
    MemberJpaRepository memberJpaRepository;

    @Test
    public void testMember() {

        Member member = new Member("memberA");
        Member savedMember = memberJpaRepository.save(member);

        Member findMember = memberJpaRepository.find(savedMember.getId());

        assertThat(findMember.getId()).isEqualTo(member.getId());
        assertThat(findMember.getUsername()).isEqualTo(member.getUsername());
        assertThat(findMember).isEqualTo(member); //JPA 엔티티 동일성 보장
    }

    @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(member1);
        assertThat(findMember2).isEqualTo(member2);

        //리스트 조회 검증
        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 = "jpabook.jpashop.repository")
public class AppConfig {}
  • 스프링 부트 사용시 @SpringBootApplication 위치를 지정(해당 패키지와 하위 패키지 인식)
  • 만약 위치가 달라지면 @EnableJpaRepositories 필요

 

 

⚡ 스프링 데이터 JPA가 구현 클래스 대신 생성

  • org.springframework.data.repository.Repository 를 구현한 클래스는 스캔 대상
    • MemberRepository 인터페이스가 동작한 이유
    • 실제 출력해보기(Proxy)
    • memberRepository.getClass() class com.sun.proxy.$ProxyXXX
  • @Repository 애노테이션 생략 가능
    • 컴포넌트 스캔을 스프링 데이터 JPA가 자동으로 처리
    • JPA 예외를 스프링 예외로 변환하는 과정도 자동으로 처리

 

 

 

📌 공통 인터페이스 적용

⚡ 스프링 데이터 JPA 기반 MemberRepository

 public interface MemberRepository extends JpaRepository<Member, Long>{
}

 

MemberRepository 테스트

package study.datajpa.repository;

import org.assertj.core.api.Assertions;
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.*;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@Transactional
@Rollback(value = false)
class MemberRepositoryTest {

    @Autowired
    MemberRepository memberRepository;

    @Test
    public void testMember() {
        //given
        Member member = new Member("memberA");
        Member savedMember = memberRepository.save(member);

        //when
        Member findMember = memberRepository.findById(savedMember.getId()).get();

        //then
        assertThat(findMember.getId()).isEqualTo(member.getId());
        assertThat(findMember.getUsername()).isEqualTo(member.getUsername());
        assertThat(findMember).isEqualTo(member); //JPA 엔티티 동일성 보장
    }

    @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(member1);
        assertThat(findMember2).isEqualTo(member2);


        //리스트 조회 검증
        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 기반 테스트에서 사용했던 코드를 그대로 스프링 데이터 JPA 리포지토리 기반 테스트로 변경해도 동일 한 방식으로 동작

 

 

TeamRepository 생성

package study.datajpa.repository;

import org.springframework.data.jpa.repository.JpaRepository;
mport study.datajpa.entity.Team;

public interface TeamRepository extends JpaRepository<Team, Long> {
}
  • TeamRepository는 테스트 생략
  • Generic
    • T: 엔티티 타입
    • ID: 식별자 타입(PK)

 

 

📌 공통 인터페이스 분석

  • JpaRepository 인터페이스: 공통 CRUD 제공
  • 제네릭은 <엔티티 타입, 식별자 타입> 설정

 

 

⚡ 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 existsById(ID) 변경

 

✔ 제네릭 타입

  • T : 엔티티
  • ID : 엔티티의 식별자 타입
  • S : 엔티티와 그 자식 타입

 

✔ 주요 메서드

  • save(S) : 새로운 엔티티는 저장하고 이미 있는 엔티티는 병합
  • delete(T) : 엔티티 하나를 삭제 -> 내부에서 EntityManager.remove() 호출
  • findById(ID) : 엔티티 하나를 조회 -> 내부에서 EntityManager.find() 호출
  • getOne(ID) : 엔티티를 프록시로 조회 -> 내부에서 EntityManager.getReference() 호출
  • findAll(...) : 모든 엔티티를 조회 -> 정렬( Sort )이나 페이징( Pageable ) 조건을 파라미터로 제공 가능

 

cf) JpaRepository 는 대부분의 공통 메서드를 제공한다.

 

 

 

김영한님의 <실전! 스프링 데이터 JPA>을 수강하고 작성한 글입니다

 

 

 

 


PREV

 

[스프링 데이터 JPA] 2. 예제 도메인 모델

📌 예제 도메인 모델과 동작확인 ⚡ Member 엔티티 package study.datajpa.entity; import jakarta.persistence.*; import lombok.*; @Entity @Getter@Setter @NoArgsConstructor(access = AccessLevel.PROTECTED) @ToString(of = {"id", "username", "age"

nyeroni.tistory.com

NEXT

 

[스프링 데이터 JPA] 4. 쿼리 메소드 기능

📌 쿼리 메소드 기능 3가지 메소드 이름으로 쿼리 생성 메소드 이름으로 JPA NamedQuery 호출 @Query 어노테이션을 사용해서 리파지토리 인터페이스에 쿼리 직접 정의 📌 메소드 이름으로 쿼리 생성

nyeroni.tistory.com

 

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'인프런 Spring 강의 정리 > 실전! 스프링 데이터 JPA' 카테고리의 다른 글

[스프링 데이터 JPA] 6. 스프링 데이터 JPA 분석  (0) 2024.01.24
[스프링 데이터 JPA] 5. 확장 기능  (0) 2024.01.24
[스프링 데이터 JPA] 4. 쿼리 메소드 기능  (0) 2024.01.24
[스프링 데이터 JPA] 2. 예제 도메인 모델  (0) 2024.01.24
[스프링 데이터 JPA] 1. 프로젝트 환경설정  (0) 2024.01.24
'인프런 Spring 강의 정리/실전! 스프링 데이터 JPA' 카테고리의 다른 글
  • [스프링 데이터 JPA] 5. 확장 기능
  • [스프링 데이터 JPA] 4. 쿼리 메소드 기능
  • [스프링 데이터 JPA] 2. 예제 도메인 모델
  • [스프링 데이터 JPA] 1. 프로젝트 환경설정
예롱메롱
예롱메롱
  • 예롱메롱
    예롱이의 개발 블로그
    예롱메롱
  • 전체
    오늘
    어제
    • 전체보기 (274)
      • 프로젝트 (35)
        • Wedle (12)
        • 인스타그램 클론 코딩 (13)
        • 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 (10)
      • 인프런 Spring 강의 정리 (79)
        • 스프링 입문 - 코드로 배우는 스프링 부트, 웹 .. (7)
        • Spring 핵심 원리 - 기본편 (9)
        • 모든 개발자를 위한 HTTP 웹 기본 지식 (8)
        • 자바 ORM 표준 JPA 프로그래밍 - 기본편 (11)
        • 실전! 스프링 부트와 JPA 활용1 - 웹 애플리.. (6)
        • 실전! 스프링 부트와 JPA 활용2 - API 개.. (5)
        • 실전! 스프링 데이터 JPA (7)
        • 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 (7)
        • 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 (11)
        • 실전! Querydsl (8)
      • Cloud (3)
      • Spring (6)
        • spring boot (5)
        • 소셜로그인 (1)
      • Docker (2)
      • DevOps (0)
      • Coding Test (114)
        • Programmers (37)
        • Baekjoon (76)
      • KB It's Your Life 6기 (1)
      • CS (18)
        • 알고리즘 (13)
        • 컴퓨터 구조 (1)
        • Operating System (0)
        • Network (0)
        • Database (4)
      • git (1)
      • Language (15)
        • Java (5)
        • C++ (6)
        • Python (4)
    • GITHUB GITHUB
    • INSTAGRAM INSTAGRAM
  • hELLO· Designed By정상우.v4.10.3
예롱메롱
[스프링 데이터 JPA] 3. 공통 인터페이스 기능
상단으로

티스토리툴바