jujuwon
시크릿주주
jujuwon
전체 방문자
오늘
어제
  • 분류 전체보기 (106)
    • 🔠 프로그래밍언어 (35)
      • ☕️ Java (19)
      • 🐠 Python (15)
      • 🍠 Kotlin (1)
    • 🔙 Backend (16)
      • 🌿 Springboot (12)
      • 🐳 Docker (1)
      • ☁️ AWS (3)
    • 💼 CS (12)
      • 📶 Network (12)
    • 🕹 알고리즘 (14)
      • 📑 스터디 (2)
      • 💁🏻‍♂️ 백준 (9)
      • 👨🏼‍🔬 프로그래머스 (3)
    • 📚 Book (8)
      • 🔎 오브젝트 (4)
      • 🧪 TDD (2)
      • 📜 논문 (2)
    • 🔐 보안 (7)
      • 👾 Pwnable (7)
    • 📝 회고 (4)
    • 🧩 etc. (10)
      • ⚠️ issue (2)
      • 💡 꿀팁 (7)
      • ✏️ 끄적 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

최근 글

hELLO · Designed By 정상우.
jujuwon

시크릿주주

Spring Boot :: Spring Data JPA
🔙 Backend/🌿 Springboot

Spring Boot :: Spring Data JPA

2022. 8. 15. 09:58
반응형

인터페이스만 정의해도 CRUD 기능을 사용할 수 있다 ?

 

테스트 코드를 통해서 CRUD 기능이 동작하는지 간단하게 테스트해보자.

 

테스트 순서

  • Entity 생성
  • 순수 JPA Repository 생성 후 테스트
  • Data JPA Repository 생성 후 테스트

 

Entity 생성


먼저 Member Entity 를 만들자.

@Entity
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {"id", "username"})
public class Member {

    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    private String username;

    public Member(String username) {
        this.username = username;
    }
}

 

순수 JPA Repository


Data-JPA 를 사용하기 전에 순수 JPA 로 CRUD 기능을 만들어보았다.

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

 

잘 동작하는지 테스트 코드로 확인해보자.

 

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

    @Autowired MemberJpaRepository memberJpaRepository;

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

        findMember1.setUsername("member!!!!!");

        // 리스트 조회 검증
        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);
    }
}

 

정상적으로 성공하는 것을 볼 수 있다.

 

 

Data JPA Repository


그렇다면 이제, Data-JPA Repository 를 만들고 Test 해보자.

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

 

끝났다 ..!

JpaRepository 를 상속받고 <대상 Entity, PK 타입> 만 지정하면 CRUD 기능을 그대로 사용할 수 있다 !

위 테스트 코드 그대로 테스트를 진행해보자 !

테스트 코드에서 Repository 만 MemberJpaRepository 가 아닌 MemberRepository 로 변경하고 진행하자.

 

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

    @Autowired
    MemberRepository memberRepository;

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

        findMember1.setUsername("member!!!!!");

        // 리스트 조회 검증
        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);
    }
}

 

동일하게 성공..!

 

 

이게 어떻게 가능한걸까 ?

JpaRepository 는 여러 interface 를 상속받고 있는데

그 중에 CrudRepository 라는 곳에 기본적인 기능들이 정의되어 있다.

 

 

물론 이 글에선 일부러 Data-JPA 인터페이스에서 제공하는 함수 이름과

동일하게 순수 JPA Repository 의 함수 이름을 동일하게 설정했지만,

어쨌든 이런 기능을 이미 제공하고 있기 때문에 공통 인터페이스의 중복 코드를 줄일 수 있다 !

사실 여기서 끝이 아니다.

메소드 이름으로 쿼리를 생성하는 등의 기능이 더 있지만 일단은 여기까지만 알아보자 ㅎㅎ

 

인터페이스만 있는데 어떻게 ?

👉 Spring Data JPA 가 구현체를 만들어서 주입해준다 ‼️

 

 

실제로 인터페이스인 Repository 클래스를 찍어보자.

 

 

위와 같이 가짜 Proxy 객체를 만들어서 주입해준 것을 확인할 수 있다.

Data JPA interface 를 만들면 @Repository 어노테이션을 생략할 수 있다.

컴포넌트 스캔을 Data JPA 가 자동으로 처리하고,

JPA 예외를 스프링 예외로 변환하는 과정도 자동으로 처리한다.

728x90
반응형
저작자표시 (새창열림)
    '🔙 Backend/🌿 Springboot' 카테고리의 다른 글
    • JPA :: Query Method 기능
    • Spring Boot :: Spring Data 패키지 구조
    • JPA :: Auditing 엔티티 공통 정보 추가하기
    • JUnit :: Test 실패 - No tests found for given includes
    jujuwon
    jujuwon

    티스토리툴바