자라나라 개발머리

2. 스프링 부트 - MySQL 연결 (JPA 사용) 본문

프로젝트/개인

2. 스프링 부트 - MySQL 연결 (JPA 사용)

iammindy 2023. 1. 28. 20:59

오늘은 스프링 프로젝트를 DB와 연결하고 테스트까지 해본다.

0편에서 스프링과 MySQL을 연결할 때 Mybatis를 쓴다길래 무작정 그렇게 해보려고 정했었다.

그러나 이후에 구글링 더 해보니 Mybatis 뿐만 아니라 스프링에서 제공하는 jdbc template, jpa 등 여러 방법이 있다는 것을 알았다.

JPA가 실무에 압도적으로 많이 쓰인다는 것을 알기 때문에 찍먹이라도 해보자는 심산으로 JPA를 사용하기로 맘 먹었다!

 

MySQL 설치

설치는 쉬우니 패스!

DB와 유저도 만들어준다. 나는 MySQL Workbench로 추가했다.

 

스프링 프로젝트

참고:

1) 인프런 '스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술' - 코드 참고

2) 스프링부트 - 10분만에 안드로이드 앱, 아이폰 앱에서 사용할 수 있는 Restful API 서버 만들기

https://www.youtube.com/watch?v=nrxzK_ky3uc

 

jpa, mysql 관련 의존성 추가 (build.gradle)

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa' //jpa
    runtimeOnly 'com.mysql:mysql-connector-j' //mysql
}

 

※ 주의: 스프링의 업데이트 따라, mysql을 연동하는 코드가 달라진다.

2023.01.28일 기준으로는 위 코드가 실행되지만 이후에는 안 될 수 있다! (때문에 며칠 고생했다)

의존성 추가 후 코끼리 눌러서 Reload 하는거 잊지 말고! 추가 했는데 load가 안 되는 오류가 뜨면 좌측 External Libraries에서 추가 됐는지 확인하자!

 

 

jpa, mysql 관련 프로퍼티 추가 (application.properties)

# database
spring.datasource.driver-class-name:com.mysql.cj.jdbc.Driver
spring.datasource.url: jdbc:mysql://localhost:3306/{DB 이름}?serverTimezone=UTC&characterEncoding=UTF-8
spring.datasource.username: {유저 이름}
spring.datasource.password: {유저 패스워드}

# jpa
spring.jpa.show-sql=true
spring.jpa.hibernate.dialect: org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=create

 

코드 작성

전 게시글에서 추가된 부분이 있다. 회원을 삭제하는 기능을 넣었다. 따라서 레포지토리 뿐만 아니라 서비스와 컨트롤러도 조금씩 수정을 했다.

 

수정 된 코드들

MemberController.java

package com.example.spring.controller;

import com.example.spring.domain.Member;
import com.example.spring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

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

@RestController
public class MemberController {

    private final MemberService memberService;
    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }

    @GetMapping("/Member/{id}")
    public Optional<Member> getMember(@PathVariable("id") Long id) {
        return memberService.findOne(id);
    }

    @GetMapping("/Member/all")
    public List<Member> getAllMember() {
        return memberService.findMembers();
    }

    @PutMapping("/Member/new/{name}")
    public void putMember(@PathVariable("name") String name) {
        Member member = new Member();
        member.setName(name);

        memberService.join(member);
    }

    @DeleteMapping("/Member/{id}")
    public void deleteMember(@PathVariable("id") Long id) { memberService.removeOne(id); }


}

 

MemberService.java

package com.example.spring.service;

import com.example.spring.domain.Member;
import com.example.spring.repository.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Transactional
public class MemberService {

    private final MemberRepository memberRepository;
    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    public Long join(Member member) {
        validateDuplicateMember(member); //중복 회원 검증
        memberRepository.save(member);
        return member.getId();
    }
    private void validateDuplicateMember(Member member) {
        memberRepository.findByName(member.getName())
                .ifPresent(m -> {
                    throw new IllegalStateException("이미 존재하는 회원입니다.");
                });
    }

    public List<Member> findMembers() {
        return memberRepository.findAll();
    }
    public Optional<Member> findOne(Long memberId) {
        return memberRepository.findById(memberId);
    }

    public void removeOne(Long memberId) { memberRepository.removeById(memberId); }

}

MemberRepository.java

package com.example.spring.repository;

import com.example.spring.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();
    void removeById(Long id);
}

 

회원 레포지토리 구현체 작성 및 변경

지난번엔 메모리에 저장이 되는 MemoryMemberRepository 사용했지만,

이제 JpaMemberRepository로 바꿔끼울 것이다!

 

JpaMemberRepository.java 작성

package com.example.spring.repository;

import com.example.spring.domain.Member;
import org.springframework.stereotype.Repository;

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

@Repository
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;
    }

    @Override
    public void removeById(Long id) {
        Member member = em.find(Member.class, id);
        em.remove(member);
    }
}

 

SpringConfig.java 에서 의존관계 변경

package com.example.spring;

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

import javax.persistence.EntityManager;

@Configuration
public class SpringConfig {

    private EntityManager em;

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

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

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

끝!

 

테스트

오늘도 postman을 사용해 테스트를 한다.

 

put 성공! (우측하단 200ok 뜨면 됨!) > android, spring, java 생성함

 

delete 성공! ( id가 3에 해당되는 유저 삭제 요기선 android가 3번이었다)

 

get 성공! 3번 삭제 후 2개가 남아있는 모습이다.

 

연결 및 테스트 성공!