Web/JPA

[Data JPA] EP 1. 공통 인터페이스 기능

 

 

 

공통 인터페이스 설정

 

Data JPA를 사용하는 방법

  1. Repository를 interface로 만듭니다.
  2. JpaRepository를 상속받는데 이때 <엔티티, 식별자 type> 을 넣어주시면 됩니다.

 

 

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.Optional;

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() throws Exception {
        //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);
    }

}

 

 

interface이고 구현체가 없는데 테스트가 동작합니다.

@Autowired로 주입받은 memberRepository가 어떤녀석인지 한번 찍어봅시다.

 

System.out.println(memberRepository.getClass());

 

프록시 가짜 클래스가 주입되어 있습니다.

Spring Data JPA가 구현체를 만들어서 넣어주는 것입니다.

 

이 외에도 컴포넌트 스캔을 스프링 데이터 JPA가 자동으로 처리해주기 때문에 @Repository 어노테이션 생략이 가능합니다.

 

 

다른 구현체들도 테스트동작이 성공합니다.

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 java.util.Optional;

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() throws Exception {

        System.out.println(memberRepository.getClass());
        //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);
    }

    @Test
    public void basicCRUD() throws Exception {
        //given
        Member member1 = new Member("member1");
        Member member2 = new Member("member2");
        memberRepository.save(member1);
        memberRepository.save(member2);
        //when

        // 단건조회
        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);

        //then
    }
}

 

 

 

공통 인터페이스 구성

 

 

JpaRepository의 경로를 보면 springframework.data.jpa.repository 로 되어있습니다.

 

사실 springframework.data 라는 공통 프로젝트에서 공통 CRUD를 제공하고,

JPA에 특화된 Repository를 제공하는것이 JpaRepository입니다.

 

예를들어서 하나만 살펴보자면,

JpaRepository가 상속받고있는 PagindAndSortingRepository는 data.repository로 되어있습니다.

기본적으로 paging, sorting은 어떤 데이터베이스든 필요한 기능이기 때문입니다.

 

 

 

 

 

 

 

주요 메서드

제네릭타입

T : 엔티티

ID : 엔티티의 식별자 타입

S : 엔티티와 그 자식 타입

 

  • save(S) : 새로운 엔티티는 저장하고 이미 있는 엔티티는 병합한다.
  • delete(T) : 엔티티 하나를 삭제한다.
    내부에서 'EntityManager.remove()' 호출
  • findById(ID) : 엔티티 하나를 조회한다.
    내부에서 'EntityManager.find()' 호출
  • getOne(ID) : 엔티티를 진짜 엔티티가 아니라 프록시로 조회한다. (사용될때 쿼리가 날아간다.)
    내부에서 'EntityManager.getReference()' 호출
  • findAll(...) : 모든 엔티티를 조회한다. 정렬('Sort')나 페이징('Pageable')조건을 파라미터로 제공할 수 있다.