04 회원 도메인 개발 - Member Repository

shin·2023년 8월 27일
0

[ 구현 기능 ]

  • 회원 등록
  • 회원 단건 조회
  • 회원 다건 조회
  • 회원 이름으로 조회

1. Member Repository

  • 패키지 구조는 계층형 구조이기 때문에 jpashop 아래에 repository 패키지를 추가한 후 해당 패키지에 회원 리포지토리를 추가함

1) Member Repository 구현

package jpabook.jpashop.repository;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jpabook.jpashop.domain.Member;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class MemberRepository {

    @PersistenceContext
    private EntityManager em;

    public void save(Member member){
        em.persist(member);
    }

    public Member findOne(Long id){
        return em.find(Member.class, id);
    }

    public List<Member> findAll(){
        return em.createQuery("select m from Member m", Member.class)
                .getResultList();
    }

    public List<Member> findByName(String name){
        return em.createQuery("select m from Member m where m.name = :name", Member.class)
                .setParameter("name", name)
                .getResultList();
    }

}


2) 코드 상세 설명

@Repository

@Repository
public class MemberRepository {
  • @Repository
    • 스프링 빈으로 등록(Component scan 대상이기 때문에)
    • JPA 예외를 스프링 기반 예외로 예외 반환

@PersistenceContext - EntityManger

 @PersistenceContext
private EntityManager em;
  • @PersistenceContext : EntityManager 주입
  • @PersistenceUnit : EntityManagerFactory 주입

save() - EntityManager.persist(entity)

public void save(Member member){
    em.persist(member);
}
  • 영속성 컨텍스트에 member entity를 저장
  • EntityManager를 통해 영속성 컨텍스트에 접근
    • 실제로 DB에 저장하는 것이 아니라 영속성 컨텍스트를 통해서 Entity를 영속화함
  • 이후 트랜잭션이 commit 되는 시점에 DB에 반영됨
    • DB에 insert Query가 날라가게 됨

findOne - EntityManager.find(type, pk)

 public Member findOne(Long id){
    return em.find(Member.class, id);
}
  • 멤버 단건 조회 기능
  • find(class 이름, 기본키)
  • 해당 객체를 영속성 컨텍스트로 가져오는데, 만약 이미 영속성 컨텍스트에 존재한다면 객체를 그대로 반환함
    • 객체가 프록시 객체라면 프록시 객체를 반환함

findAll - EntityManger.createQuery(jpql)

public List<Member> findAll(){
     return em.createQuery("select m from Member m", Member.class)
              .getResultList();
}
  • 멤버 전체 조회 기능
  • createQuery(jpql) : jpql을 사용해서 조회 구현
  • sql은 테이블을 대상으로 쿼리를 작성하고, createQuery에 쓰이는 jpql은 entity를 대상으로 쿼리를 작성해야 함
    • JPQL은 객체지향쿼리이기 때문에 엔티티 클래스를 기반으로 쿼리를 작성해야 함
    • JPQL로 작성된 객체지향 쿼리는 DB에 질의할 떄 SQL로 변환됨

findByName - EntityManger.createQuery(jpql)

public List<Member> findByName(String name){
    return em.createQuery("select m from Member m where m.name = :name", Member.class)
             .setParameter("name", name)
             .getResultList();
}
  • 파라미터로 name을 전달받아서 name에 의해 멤버 데이터를 조회

💡 EntityMangerFactory & EntityManger

EntityMangerFactory

  • 고객의 요청이 올 때마다(thread가 생성될때마다) EntityManager를 생성
  • application loading 시점에 DB당 딱 하나만 생성
  • 여러 스레드가 동시에 접근해도 안전함

EntityManager

  • 내부적으로 DB Connection pool을 사용해서 DB에 접근
  • 실제 transaction 단위를 수행할 때마다 생성
  • 엔티티 매니저는 여러 스레드가 동시에 접근하면 동시성 문제가 발생하기 때문에 스레드 간에 공유가 금지됨(사용 후에는 close)

💡 JPQL

(1) JPQL을 실행하면 영속성 컨텍스트가 flush

  • flush
    • 영속성 컨텍스트의 변경 내용을 DB에 동기화하는 작업
    • Transaction commit이 일어날 때, flush가 동작함
    • 쓰기 지연 저장소에 쌓아놨던 sql query가 DB에 날라감
  • 영속성 컨텍스트가 flush 되는 경우는 flush 메서드를 호출하거나 트랜잭션이 종료되는 경우
  • JPQL을 이용하게 되면 실행 시점에 영속성 컨텍스트가 flush 됨

(2) JPQL로 조회한 엔티티는 영속 상태가 됨

  • JPQL을 이용해서 쿼리를 실행하면 리턴받는 엔티티들은 모두 영속 상태가 됨
    • JPQL 실행하면 영속성 컨텍스트로 요청을 보냄
    • 영속성 컨텍스트는 1차 cash에 엔티티 존재 여부와 관계 없이 DB에 질의를 함
    • DB 질의를 통해 조회된 데이터를 영속성 컨텍스트가 전달 받음
    • 엔티티를 초기화하고 cash에 저장
    • 다시 엔티티를 반환


강의 : 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

profile
Backend development

0개의 댓글