[스프링 입문] Section07. 스프링 DB 접근 기술[5] - JPA

Euiyeon Park·2025년 6월 17일
0

갓영한 스프링🍀

목록 보기
9/12
post-thumbnail

JPA(Java Persistence API)

  • JPA는 기존의 반복 코드와, 기본적인 SQL도 JPA가 직접 만들어서 실행
  • JPA를 사용하면 SQL와 데이터 중심 설계에서 객체 중심 설계가 가능
  • JPA는 인터페이스만 제공, 구현체는 Hibernate(또는 여러 기술 벤더들이 있음
  • JPA는 ORM 기술 - 객체(Object)와 RDB(Relational) 매핑
    • 어떻게 매핑? 어노테이션(@Entity)으로 매핑

📂 build.gradle

  • JPA 관련 라이브러리 추가
    • JPA 라이브러리는 내부에 JDBC 관련 라이브러리를 추가
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

📂 application.properties

  • 스프링 부트에 JPA 설정 추가
  • show-sql : JPA가 생성하는 SQL을 출력
  • ddl-auto=none : JPA의 테이블 자동 생성 기능을 끔
    • create : 애플리케이션 실행 시 기존 테이블 삭제 후 새로 생성
    • create-drop : 애플리케이션 실행 시 테이블 생성, 종료 시 테이블 삭제
    • update : 데이터베이스 스키마를 매핑 정보와 비교해 필요한 부분만 변경
    • validate : 데이터베이스와 매핑 정보 검증만 수행
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none

📂 Member

  • JPA 엔티티 매핑
  • @Entity : 데이터베이스 테이블과 매핑되는 클래스 명시
  • @Id : 기본 키 지정
  • @GeneratedValue(strategy = GenerationType.IDENTITY) : 기본 키 자동 생성 전략
    • GenerationType.IDENTITY : DB의 AUTO_INCREMENT 기능 사용
    • GenerationType.SEQUENCE : DB의 시퀀스를 사용(Oracel, PostgreSQL)
    • GenerationType.TABLE : 별도의 키 관리 테이블 사용
    • GenerationType.AUTO : DB에 맞는 전략을 자동 선택
@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;}
}

📂 JpaMemberRepository

  • JPA를 사용하기 위해 트랜잭션 필요 - MemberService에 @Transactional 추가
    • JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행
  • JPA는 EntityManager로 동작
    • build.gradle에서 JPA관련 라이브러리를 받으면 스프링 부트가 EntityManager를 생성
    • JPA를 사용하려면 EntityManager를 주입받아야 함
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) {
        // find(조회할 타입, 식별자(PK))
        Member member = em.find(Member.class, id);
        return Optional.ofNullable(member);
    }

    @Override
    public Optional<Member> findByName(String name) {
        // 📌 PK가 아닌 다른 컬럼으로 조회시 JPQL을 사용
        // JPQL은 테이블 대상 쿼리가 아닌 객체(엔티티) 대상 쿼리
        // SELECT 의 대상은 엔티티
        List<Member> member = em.createQuery("select m from Member m where m.name = :name", Member.class)
                .setParameter("name", name)
                .getResultList();

        return member.stream().findAny();
    }

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

EntityManager, PC, EntityManagerFactory

🍀 1. EntityManager

  • JPA에서 제공하는 엔티티 관리 인터페이스
  • 엔티티의 생성, 조회, 수정, 삭제와 같은 데이터 조작 작업을 수행
  • EntityManager는 내부에 Persistence Context를 둬서 엔티티들을 관리

핵심 역할

  • 영속성 컨텍스트 관리
  • 트랜잭션 관리
  • 쿼리 실행 및 데이터베이스 연결 관리

생명 주기

  • 단일 트랜잭션 또는 작업 단위에서만 유효
  • 트랜잭션이 종료되거나 close() 메서드가 호출되면 더 이상 사용❌

🍀 2. 영속성 컨텍스트(Persistence Context)

  • 엔티티 객체를 관리하는 메모리 공간
  • EntityManager가 관리하는 1차 캐시 역할
  • 객체의 상태를 추적하고 동기화

주요 특징

  1. 1차 캐시
  • 동일 트랜잭션 내에서 동일 엔티티 조회 시,
    데이터베이스 재조회 없이 메모리에서 가져옴
  1. 변경 감지(Dirty Checking)
  • 엔티티의 상태가 변경되면 자동으로 업데이트 쿼리를 생성하고 반영
  1. 쓰기 지연(Wrire Behind)
  • 트랜잭션이 커밋될 때까지 SQL 쿼리를 지연 저장하여 성능 최적화
  • 트랜잭션이 커밋 되기 전까지 모든 쿼린문은 영속성 컨텍스트 내부의
    쓰기 지연 SQL 저장소에 저장 - 커밋되는 순간 모든 쿼리를 한 번에 날림
  1. 동기화(Flush)
  • 영속성 컨텍스트와 데이터베이스를 동기화

상태 변화

User user = new User();   // 비영속 (Transient)
em.persist(user);         // 영속 (Persistent)
em.detach(user);          // 준영속 (Detached)
em.remove(user);          // 삭제 (Removed)
  1. 비영속(Transient) : 아직 영속성 컨텍스트에 포함되지 않은 상태
  2. 영속(Persistent) : persist() 호출 후 관리되는 상태
  3. 준영속(Detached) : detach() 또는 clear() 호출 시 관리가 해제된 상태
  4. 삭제(Removed) : remove() 호출 후 삭제 예약 상태

🍀 3. EntityManagerFactory

  • EntityManager 인스턴스를 생성하는 팩토리 클래스
  • JPA 설정(데이터베이스 연결, 매핑 정보)를 기반으로 애플리케이션 전체에서 공유
  • 애플리케이션 실행 시 한 번만 생성해야 함

주요 특징

  • 애플리케이션당 하나의 인스턴스만 사용
  • Thread-Safe : 멀티스레드 환경에서 안전하게 사용 가능
  • 데이터베이스 연결 정보 및 설정을 포함
  • 성능 최적화를 위해 커넥션 풀링을 지원
EntityManagerFactory emf = Persistence.createEntityManagerFactory("example-unit");
EntityManager em1 = emf.createEntityManager(); // EntityManager 생성
EntityManager em2 = emf.createEntityManager(); // 또 다른 EntityManager 생성

em1.close();
em2.close();
emf.close(); // 최종 종료

🍀 정리

  1. EntityManagerFactory 생성 : 전체 애플리케이션에서 하나만 생성
  2. EntityManager 생성 : 각 작업 단위(트랜잭션)에 대해 생성
  3. 영속성 컨텍스트 관리 : 데이터베이스와 메모리 간 상태 동기화
profile
"개발자는 해결사이자 발견자이다✨" - Michael C. Feathers

0개의 댓글