[Spring boot] 회원관리 예제 만들기 3

Ho·2022년 7월 5일
0

Spring Boot 입문

목록 보기
7/7

앞에 만든 회원관리 예제는 회원 데이터를 MemoryMemberRepository 클래스의 객체에 저장한다. 서버가 실행되면서 객체가 생성되고 데이터가 저장되었다. 하지만 서버를 종료하는 순간 메모리 상의 객체는 사라지기 때문에 데이터를 보관할 수 없다.

H2 database를 설치하고 데이터를 데이터베이스에 저장하는 방식으로 repository를 변경해보려고 한다.


h2 database 설치하기

http://www.h2database.com/html/main.html 에 접속하여
os에 맞는 버전을 설치한다.
압축을 풀고 bin 안에 있는 h2.sh을 실행한다.
Jdbc url: jdbc:h2:~/test 로 설정하고 연결한다.
홈 디렉토리에 test.mv.db 파일이 생성되었는지 확인하고
이후부터는 Jdbc url을 jdbc:h2:tcp://localhost/~/test 로 설정하여 연결하면 된다.


객체지향적인 설계가 좋은 이유

인터페이스를 설계하고 구현체를 바꾸며 사용할 수 있다 -> 다형성을 활용한다.
스프링에서는 스프링컨테이너가 Dipendency Injection을 해주어 이를 가능하게 한다.

기존의 코드는 건드리지 않고 어플리케이션을 어셈블하는 코드만 수정한다면 손쉽게 변경이 가능하다.

MemberService 는 MemberRepository 에 의존하고 있다
MemberService 객체가 생성될때 MemberRepository 를 주입받는다. Configuration 에서 MemberRepository를 스프링빈으로 등록할 때 어떤 구현체를 생성하여 인터페이스에 담을지만 변경한다면 기존 코드에 영향을 주지 않고 리포지토리를 변경할 수 있다.

데이터베이스에 데이터를 저장하기 위해 Jpa를 사용한다.


JPA (Java Persistence API)

JPA는 자바 ORM 표준 기술이다. ORM 이란 Object Relation Mapping 의 약어로 객체-관계 매핑을 뜻한다. 자바 어플리케이션의 객체와 관계형 데이터베이스에서의 엔티티를 매핑하여 관계형 데이터베이스에 객체의 데이터를 저장할 때 자바 콜렉션에 넣는 것과 같이 사용할 수 있도록 해주는 api이다.

간단한 사용법만 알아보고 이후 깊이 있게 다루어볼 예정이다.


repository 변경하기

Build.gralde에서 dependencies에 Jpa를 추가한다.

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

데이터베이스에 데이터를 저장할 수 있는 JpaMemberRepository를 구현한다.


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() {
        List<Member> result = em.createQuery("select m from Member m", Member.class).getResultList();
        return result;
    }
}

인터페이스가 포함하는 메서드를 구현한다.

엔티티와 매핑할 객체에 어노테이션을 붙인다.

@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;
    }
}
  • @Entity: 매핑할 객체를 지정한다.
  • @Id : Primary key에 해당하는 필드 지정
  • @GeneratedValue: 값이 null 일때 default로 자동 생성

Jpa를 쓰려면 트랜잭션이 있어야한다.
MemberRepositry의 메서드를 호출하는 MemberService 클래스에 @Transactional 어노테이션을 사용한다.

@Transactional
public class MemberService {
	...
}

Configuration에서 MemberRepositry의 구현체를 변경하면 된다.

@Configuration
public class SpringConfig {

    private EntityManager em;

    @Autowired
    public SpringConfig(EntityManager em) {
        this.em = em;
    }

    @Autowired private MemberRepository memberRepository;

    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository);
    }

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

}

스프링부트가 실행될 때 EntityManager를 생성해서 가지고있는다. Jpa에서 사용할 클래스를 구현할 때 생성자로 주입 받으면 된다.


Configuration에서 MemberRepository에 구현체를 바꾸는 것 만으로 기존 코드에 영향을 주지 않고 리포지토리를 변경할 수 있었다. 스프링의 DI는 이러한 다형성을 활용할 수 있도록 해준다.

0개의 댓글