스프링 데이터 JPA에 공통 인터페이스

구본식·2023년 2월 3일
1

Spring Data JPA

목록 보기
2/8
post-thumbnail

1. 순수 JPA기반 레포지토리

Spring Data JPA를 사용하여 기본 CRUD를 사용하기전에 Spring Data JPA가 제공해주는 기능들을 직접 구현해보고자 한다.

Member Entity

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED) //private X -> 프록시가 객체를 만들때 오류가 발생
@ToString(of = {"id", "username", "age"}) //출력할때 찍은 컬렴들 지정 가능
public class Member {

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

    private String username;

    private Integer age;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
    private Team team;

    //생성자
    public Member(String username) {
        this.username = username;
    }
    public Member(String username, int age, Team team) {
        this.username = username;
        this.age = age;
        if(team != null) //단순하게 null 처리 -> 실제로는 예외 발생시키는 로직으로 설계
            changeTeam(team);
    }

    //양방향 연관관계 매핑
    public void changeTeam(Team team){
        this.team = team;
        team.getMembers().add(this);
    }
}

MemberJpaRepository

/**
 * 순수 JPA 기반 레포지토리
 */
@Repository
public class MemberJpaRepository {

    @PersistenceContext
    private EntityManager em;

    //저장
    public Member save(Member member){
        em.persist(member);
        return member;
    }

    //단건 조회
    public Member find(Long id){
        return em.find(Member.class, id);
    }
    public Optional<Member> findById(Long id){
        Member member = em.find(Member.class, id);
        return Optional.ofNullable(member);
    }

    //복수건 조회
    //JPQL 사용
    public List<Member> findAll() {
        return em.createQuery("select m from Member m",Member.class)
                .getResultList();
    }

    //개수 조회
    //JPQL 사용, count 는 Long 타입 반환!
    public Long count() {
        return em.createQuery("select count(m) from Member m", Long.class)
                .getSingleResult();
    }

    //삭제
    public void delete(Member member){
        em.remove(member);
    }

}

테스트를 위해 Memeber Entity와 Spring Data JPA가 제공해주는 공통 인터페이스의 기능을 레포지토리로 만들어보았다.

/**
 * spring Data JPA 테스트
 */
@SpringBootTest
@Transactional
public class MemberRepositoryTest {

	@Autowired
    MemberJpaRepository memberJpaRepository;

    @Test
    public void basicCRUD() throws Exception {

        Member member1 = new Member("memberA");
        Member member2 = new Member("memberB");
        memberRepository.save(member1);
        memberRepository.save(member2);

        //단건 조회 검증
        Member findMember1 = memberRepository.findById(member1.getId()).get();
        Member findMember2 = memberRepository.findById(member2.getId()).get();
        Assertions.assertThat(findMember1).isEqualTo(member1);
        Assertions.assertThat(findMember2).isEqualTo(member2);

        //복수 조회 검증
        List<Member> all = memberRepository.findAll();
        Assertions.assertThat(all.size()).isEqualTo(2);

        //카운트 검증
        Long count = memberRepository.count();
        Assertions.assertThat(count).isEqualTo(2);

        //삭제 검증
        memberRepository.delete(member1);
        memberRepository.delete(member2);
        Long deleteCount = memberRepository.count();
        Assertions.assertThat(deleteCount).isEqualTo(0);
    }
}

테스트를 실행해보면 정상적으로 동작하게 된다.

이제 Spring Data JPA가 제공해주는 공통 인터페이스로 바꾸어보겠다.


2. 공통 인터페이스 설정 및 적용

MemberRepository

/**
 * 스프링 데이터 JPA 기반 레포지토리
 */
public interface MemberRepository extends JpaRepository<Member, Long> {
}

스프링 데이터 JPA가 제공해주는 공통 인터페이스JpaReository<T,ID>를 상속받게 하였다.
(T:엔티티 타입, ID:식별자,PK 타입)

레포지토리만 변경하여(@Autowired) 위에서 했던 테스트 코드를 그대로 실행시켜보면 정상적으로
동작되는것을 알 수 있다.

그 이유를 알기 위해 간단히 공통 인터페이스를 분석해보겠다.


3. 공통 인터페이스 분석

JpaReository<T,ID>가 상속한 인터페이스들의 메서드들을 살펴보게 되면
우리가 앞서 순수 JPA로 구현했던 메서드들이 인터페이스로 모두 있는것을 알수 있다.

아래와 같이 공통 인터페이스의 구성을 살펴보게 되면 많은 인터페이스가 있는것을 알수있다.

스프링 데이터의 부분에는 관계형 데이터베이스든 비관계형 데이터베이스든 공통으로 제공할 수 있는 기술들의 인터페이스를 모아놓았다.

스프링 데이터 JPA에는 JPA에 특화된, 관계형 데이터베이스에 특화된 기능들의 인터페이스를 모아논 곳이다.

주요 메서드들로는 save, delete, findByID 등... 공통적으로 속한 메서드들을 제공해주게 된다.

하지만 공통 메서드가 아닌 도메인에 특화된(member.name, member.age 등..) 기능들일 경우일 경우에는 spring data jpa쿼리 메소드 기능을 제공하여 이를 쉽게 구현할수 있도록 해준다.

profile
백엔드 개발자를 꿈꾸며 기록중💻

0개의 댓글