React + Spring - 데이터베이스 연동

김태훈·2023년 1월 26일
0

이전 포스트에는 회원가입을 단순 Memory로 구현했다.
이를 데이터베이스로 만들기 위한 방법을 이번 포스트에서 소개하겠다.

1. 데이터베이스 선정

이전 프로젝트에서는 h2 database에 저장했지만, 지금은 더 보편적인 MySql database를 사용하기로 했다.

그리고 데이터베이스를 간단하게 다뤄주는 JPA API를 사용해보자 !

2. 라이브러리 추가

먼저 'build.gradle' 파일에 해당 JPA 와 MySQL dependency를 추가시키고 refresh 시켜서 라이브러리를 받아오자 !

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

그 후 properties에 다음을 추가한다.
물론 MySQL 정보또한 추가시킨다.

spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:mysql://localhost:3306/new_schema?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=1234

위 내용이 뭔지 모르겠다면 눌러 !! --> "해당 property에 관해 설명했던 포스트 링크"
추가적으로, spring.datasource.url에서
mysql://localhost:3306/member
이부분을 해석하자면 mysql을 사용할 것이고, 그 이후에는 IP주소:포트번호/데이터베이스(스키마이름) 순으로 작성한다.

3. SQL 테이블 만들기

앞에서 우리는 property 에서 "ddl-auto=none" 으로 자동 테이블 생성을 막았다.
그렇다면 따로 만들어야겠다.
우리에게 필요한건 단지 Id, Password 그리고 각 회원마다 보유되는 고유 Primary Key정보이다.
해당 정보가 다 들어가게 테이블을 만들자.

CREATE TABLE `websitedb`.`member` (
    `id` INT NOT NULL,
    `username` VARCHAR(45) NOT NULL,
    `password` VARCHAR(45) NOT NULL,
    PRIMARY KEY (`id`)
);

SQL workbench에서 단순 클릭만으로 이렇게 SQL 테이블문을 만들었다.

4. ORM 설정하기

객체와 Relation DB를 Mapping 하는 것이 JPA의 역할이거늘, 이를 매핑해주기 위해 우리는 해당 DB와 연관된 Member 클래스에 "@Entity" 어노테이션 및 필요한 어노테이션들을 달아주자

package com.example.SpringAndReact.Domain;

import jakarta.persistence.*;

@Entity
public class Member {
    @Id @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Long id;
    @Column(name="username") //db column 네임과 일치함
    private String username;
    @Column(name="password")
    private String password;

    public Long getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

5. JPA Repository 만들기

JPA는 EntityManager로 동작함을 다시한번 상기하자.
Spring Boot에서는 gradle을 통해 build되어질 때, 자동으로 EntityManager를 생성하고, 우리는 이를 가져다 쓴다.

추가로, Service에도 Transactional 어노테이션을 추가하는 것 잊지말자

package com.example.SpringAndReact.Repository;

import com.example.SpringAndReact.Domain.Member;
import jakarta.persistence.EntityManager;

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

public class JpaRepository implements MemberRepository{
    private final EntityManager em;

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

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

    @Override
    public Optional<Member> findByUserId(String id) {
        List<Member> result = em.createQuery("select m from Member m where m.username = :name", Member.class)
                .setParameter("name", id)
                .getResultList();
        return result.stream().findAny();
    }
}

findByUserId 메소드 설명
먼저 createQuery를 보자.

  • Member.class는 반환 타입이다.
  • :name 은 파라미터를 정의한 것이고, 이는 setParameter함수를 통해 연쇄적으로(메소드 체인) 파라미터 바인딩이 이뤄지고 있다.

6. AppConfig 수정

EntityManager를 사용하므로 해당 객체를 가져와서 파라미터로 넘겨주자.

package com.example.SpringAndReact;

import com.example.SpringAndReact.Repository.MemoryMemberRepository;
import com.example.SpringAndReact.Service.MemberService;
import com.example.SpringAndReact.Service.MemberServiceImpl;
import com.example.SpringAndReact.controller.MemberController;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
    @PersistenceContext
    private EntityManager em;
    @Autowired
    public AppConfig(EntityManager em){
        this.em = em;
    }
    @Bean
    public MemberService memberService (){
        return new MemberServiceImpl(new MemoryMemberRepository());
    }

}

7. 문제 발생

이 문제를 해결해보자!

알고보니 @Transactional 어노테이션을 인터페이스에 붙여서 생긴 문제였다.
클래스에 붙일것!!

8. 해결 완료!

profile
기록하고, 공유합시다

0개의 댓글