Spring boot 중고거래 쇼핑몰 사이트 만들기 프로젝트 7-1 (Spring과 MySQL 연동하기, JPA 사용하기)

전승재·2023년 8월 12일
post-thumbnail

application.properties 설정

JDBC와 MySQL을 사용하기 위한 설정을 해준다.
당연히 MySQL이 깔려있어야하고 스키마 역시 생성되어있다.

build.gradle 의존성 설정

JPA와 MySQL 사용하기 위함

	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	runtimeOnly 'com.mysql:mysql-connector-j'
	implementation 'mysql:mysql-connector-java:8.0.26'// JDBC 드라이버 (사용하는 데이터베이스 종류에 맞게 선택)

Entity

  • @Entity는 JPA(Java Persistence API)에서 사용되는 어노테이션으로, 해당 클래스가 데이터베이스의 테이블과 매핑되는 엔티티(Entity) 클래스임을 표시하는 역할을 한다.
  • @Id는 primary key임을 표시한다.
  • @GeneratedValue는 자동생성되는 어노테이션이다.

Repository

  • EntityManager em;: 엔티티 매니저를 주입받기 위한 필드이다.

  • public JpaMemberRepository(EntityManager em): 생성자(Constructor)에서 EntityManager를 주입받아 필드에 할당하는 역할을 한다.

  • Member save(Member member): 회원 정보를 데이터베이스에 저장하는 메서드이다. em.persist(member)를 호출하여 엔티티를 영속화한다.

  • Optional findByLoginId(String loginId): 로그인 아이디를 기반으로 회원을 조회하는 메서드이다. JPQL(Java Persistence Query Language)을 사용하여 쿼리를 작성하고, 파라미터로 넘어온 loginId를 바인딩하여 조회한다. 결과를 리스트로 가져온 뒤 첫 번째 요소를 Optional로 감싸서 반환한다. 결과는 단 하나밖에 없기 때문에 첫 번째 요소를 가져와도 무방하다.

  • Member findById(Long id): 주어진 고유 아이디를 사용하여 회원을 조회하는 메서드이다. EntityManager의 find 메서드를 사용하여 엔티티를 조회한다.

  • List findAll(): 모든 회원을 조회하는 메서드이다. JPQL을 사용하여 모든 Member 엔티티를 가져온다.

  • @Repository: 스프링에서 리포지토리(데이터 액세스 로직) 빈으로 등록되어 사용되는 것을 나타내는 어노테이션이다.

package com.shopingmall.seungjae.repository;

import com.shopingmall.seungjae.domain.Member;
import jakarta.persistence.EntityManager;
import org.springframework.stereotype.Repository;

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> findByLoginId(String loginId) {
        // 로그인 아이디(loginId)를 기반으로 회원을 조회하는 메서드입니다.
        // JPQL을 사용하여 쿼리를 작성하고, 파라미터로 넘어온 loginId를 바인딩합니다.
        // 조회 결과를 리스트로 가져온 뒤 첫 번째 요소를 Optional로 감싸서 반환합니다.
        Optional<Member> member = em.createQuery("select m from Member m where m.loginId = :loginId", Member.class)
                .setParameter("loginId", loginId)
                .getResultList()
                .stream().findFirst();
        return member;
    }

    @Override
    public Member findById(Long id) {
        // 주어진 아이디(id)를 사용하여 회원을 조회하는 메서드입니다.
        // EntityManager의 find 메서드를 사용하여 엔티티를 조회합니다.
        Member member = em.find(Member.class, id);
        return member;
    }

    @Override
    public List<Member> findAll() {
        // 모든 회원을 조회하는 메서드입니다.
        // JPQL을 사용하여 모든 Member 엔티티를 가져옵니다.
        List<Member> members = em.createQuery("select m from Member m", Member.class)
                .getResultList();
        return members;
    }
}

Service

org.springframework.transaction.annotation.Transactional 를 사용하자.
스프링은 해당 클래스의 메서드를 실행할 때 트랜잭션을 시작하고, 메서드가 정상 종료되면 트랜잭션을 커밋한다. 만약 런타임 예외가 발생하면 롤백한다.
JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야 한다.
즉, 데이터 변경 도중에 발생하는 여러가지 예외 또는 에러들에 의해 데이터가 손상되지 않도록 트랜젝션을 사용해줘야 하는 것이다.
따라서 member를 저장하는 MemberService에 @Transactional를 붙여줘야 한다.
이 부분을 안해줘서 에러가 발생했었다! 이 부분 꼭 인지하자!!!

package com.shopingmall.seungjae.service;


import com.shopingmall.seungjae.domain.Member;
import com.shopingmall.seungjae.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor @Service @Transactional
public class MemberService {
    private final MemberRepository memberRepository;
    public String join(Member member) {
        //같은 로그인 아이디가 있는 중복 회원은 안된다.
        memberRepository.findByLoginId(member.getLoginId())
                .ifPresent(m->{
                    throw new IllegalStateException();
                });
        memberRepository.save(member); //저장
        return member.getLoginId();
    }
}

SpringConfig


기존에는 위의 사진과 같은 형태로 되어있었다. 이는 JPA를 사용하지 않을 때의 Config였다.
하지만 이제는 JPA를 사용하는 구현체로 바꾸어야 하기 때문에 아래와 같이 코드를 수정했다.

EntityManager 생성해준다.

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

결과 사진

inset문이 실행된 것으로 값이 들어갔다는 것을 유추할 수 있다.

실제 DB에 query문을 작성하여 테이블을 보니 제대로 값이 들어간것을 확인할 수 있었다.

로그인까지 성공적으로 되는것을 확인했다.

다음에 해야할 일

마찬가지로 ItemRepositoryImpl를 JpaItemRepository로 바꿔줄 예정이다.

0개의 댓글