본문 바로가기

[스프링 부트 + JPA + MySQL] 간단한 회원 관리 예제로 알아보는 스프링부트 -2탄 Repository 만들기

ironwhale 2022. 11. 14.

이번에는 DB에서 한 발자국 나아가 Repository를 만들어 보겠습니다. 리포지토리는 DB에 실제 저장, 불러오기 등의 기능을 구현하는 곳입니다. 실제 강의에서는 인터페이스를 이용해서 Memory기반에서 JDBC, JDBC Templete, JPA 순으로 다형성을 이용하여 구현하는 방법을 배웠으나, 저는 JPA만 가지고 구현하고 테스트 코드까지 정리해보겠습니다.


도메인 만들기

  • 도메인은 아마도 MVC 모델에서 M에 해당하는 부분이 아닐까 추측해봅니다.
  • 이 도메인은 우리가 다룰 데이터의 자료형이라고 생각하시면 됩니다.
  • 저장할때도 Member 객체를 만들어서 저장할 것이고, 사용할때도 Memeber 객체를 이용하여 사용할 것입니다.

JPA 관련 설정

  1. @Entity: DB 테이블을 매핑
  2. @Id: 이것을 pk로 지정한다는 부분
  3. @GeneratedValue(strategy = GenerationType.IDENTITY): 자동으로 생성하는데 identity는 DB에서 자동으로 생성한다는 뜻
package com.example.demo.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


}

인터페이스 만들기

  • save: DB에 저장
  • findAll(): DB에 저장된 모든 멤버들 불러오기
  • findByID: pk를 이용해서 멤버 한개 불러오기
  • findByName: 멤버 이름을 검색해서 불러오기
package com.example.demo.repository;

import com.example.demo.domain.Member;

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

public interface MemberRepository {
    Member save(Member member);
    Optional<Member> findById(long id);
    Optional<Member> findByName(String name);
    List<Member> findAll();
}

CRUD 중 C와 R 부분만 구현하였습니다. 이제 인터페이스를 이용한 구현체를 만들어 볼 차례입니다.


JPA 구현체 만들기

MemberRepository를 이용해 여러 DB를 이용할 수 있는 구현체를 만들 수 있는데 저는 JPA를 이용할 수 있는 구현체를 만들어 보았습니다.

  • JPA를 사용하기 위해서는 EntityManager를 이용하면 되는데 생성자를 이용하여 주입해주도록 하겠습니다.
  • 이 부분은 추후 @Bean을 이용하여 JPA를 스프링이 이용하도록 설정하는 곳에서 EntityManager를 주입합니다.
package com.example.demo.repository;

import com.example.demo.domain.Member;

import javax.persistence.EntityManager;
import java.util.List;
import java.util.Optional;

public class JpaMemberRepository implements MemberRepository {
    private final EntityManager em;

    public JpaMemberRepository(EntityManager em) {
        this.em = em;
    }

    @Override
    public Member save(Member member) {
        em.persist(member);
        return member;
    }

    @Override
    public Optional<Member> findById(long id) {
        Member member = em.find(Member.class, id);
        return Optional.ofNullable(member);
    }

    @Override
    public Optional<Member> findByName(String name) {
        List<Member> result = em.createQuery("SELECT m FROM Member m where m.name =: name", Member.class)
                .setParameter("name", name)
                .getResultList();
        return result.stream().findAny();
    }

    @Override
    public List<Member> findAll() {
        return em.createQuery("SELECT m FROM Member m", Member.class).getResultList();
    }
}

JPA 사용 설정

이제 스프링에서 JPA를 사용하도록 @Configuration을 이용해서 설정하도록 하겠습니다.

  • 아래 와 같이 코드를 입력하면 자동으로 스프링에서 JpaMemberRepository로 EntityManager를 주입해줍니다.
  • 아울러 new JpaMemberRepository(em) 부분을 다른 구현체로 바꿔주면 JDBC, JDBC Templete을 사용할 수도 있습니다.
package com.example.demo;

import com.example.demo.repository.JpaMemberRepository;
import com.example.demo.repository.MemberRepository;
import com.example.demo.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.EntityManager;

@Configuration
public class SpringConfig {

    private final EntityManager em;
    
    public SpringConfig(EntityManager em) {
        this.em = em;

    @Bean
    public MemberRepository memberRepository(){
        return new JpaMemberRepository(em);
    }
}

테스트 코드 작성

간단하게 방금 만든 레포지토리를 테스트 하는 코드를 작성하였습니다. DB에 저장을 하고 저장된 값을 불러와서 앞서 저장된 값과 비교하는 코드입니다.

  • @SpringBootTest: 스프링이 구동되면서 해당 함수 부분만 테스트 해봅니다.
  • @Transactional: JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야 하기 때문에 필요하다는데 좀 더 공부가 필요한 부분인거 같습니다. 저는 그냥 몬가 DB에 데이터를 변경하는 클래스에는 @Transactional을 붙여준다라고 알고 넘어 갔습니다.
package com.example.demo.repository;

import com.example.demo.domain.Member;
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 javax.transaction.Transactional;


@SpringBootTest
@Transactional
class JpaMemberRepositoryTest {

    @Autowired
    MemberRepository memberRepository;

    @Test
    void 저장하기() {
        //given
        Member member = new Member();
        member.setName("test");

        //when
        memberRepository.save(member);

        //then
        // 저장된 멤버 꺼네오기
        Member m1 = memberRepository.findById(member.getId()).get();
        Assertions.assertThat(m1).isEqualTo(member);
    }
}

이제 DB에 저장하고 불러오는 부분을 만들었습니다. 다음에는 이 repository를 이용하여 실제 동작하는 서비스 부분을 만들어 보겠습니다.

이전편

2022.11.14 - [스프링 부트 + JPA + MySQL] 간단한 예제로 알아보는 스프링부트 -1탄 DB 설정편

댓글