SEB_BE 49일차 - JPA 기반 데이터 액세스 계층1

subimm_·2022년 11월 1일
0

코드스테이츠

목록 보기
49/83

💡 오늘의 학습목표

  • JPA
  • JPA 엔티티 매핑과 연관 관계 매핑

📔 JPA(Java Persistence API)

📖 JAP란?

  • Java 진영에서 사용하는 ORM(Object-Relational Mapping)기술의 표준 사양
    • Java의 인터페이스로 사양이 정의되어 있기 때문에 JPA라는 표준 사양을 구현한 구현체는 따로 있음.
    • Jakarta Persistence 라고도 함.
  • Hibernate ORM
    • JPA에서 정의해둔 인터페이스를 구현한 구현체
    • JAP에서 지원하는 기능 이외에 Hibernate 자체적으로 사용할 수 있는 API도 지원

📖 데이터 액세스 계층에서의 JPA 위치

  • 데이터 액세스 계층의 상단에 위치

  • 데이터 저장, 조회 등의 작업은 JPA를 거쳐 JPA의 구현체인 Hibernate ORM을 통해서 이루어지며 Hibernate ORM은 내부적으로 JDBC API를 이용해서 데이터베이스에 접근

📖 JPA 에서 P (Persistence)의 의미

  • 영속성. 무언가를 금방 사라지지 않고 오래 지속되게 한다.

  • 영속성 컨텍스트

    • ORM은 객체와 데이터베이스 테이블의 매핑을 통해 엔티티 클래스 객체 안에 포함된 정보를 테이블에 저장하는 기술
    • JAP에서는 테이블과 매핑되는 엔티티 객체 정보를 영속성 컨텍스트에 보관해서 오래 지속함.
    • JPA API 중에서 엔티티 정보를 영속성 컨텍스트에 저장하는 API를 사용하면 1차 캐시에 저장.

📖 JPA API로 영속성 컨텍스트 이해하기

JPA API를 사용하기 위한 사전 준비

  • build.gradle 설정
  • JPA 설정
  • (1) 설정을 추가하면 JPA에서 사용하는 엔티티 클래스를 정의하고 애플리케이션 실행 시, 엔티티와 매핑되는 테이블을 데이터베이스에 자동 생성
  • (2) JPA API를 통해서 실행되는 SQL쿼리를 로그로 출력

샘플 코드 실행을 위한 Configuration 클래스 작성

  • (1)과 같이 애너테이션을 추가하면 Spring에서 Bean 검색 대상인 Configuration 클래스로 간주해서 (2) @Bean 애너테이션이 추가된 메서드를 검색하여 해당 메서드에서 리턴하는 객체를 Spring Bean으로 추가해 준다.
  • (3)과 같은 CommandLineRunner 객체를 람다표현식으로 정의해주면 애플리케이션 부트스트랩 과정이 완료된 후에 람다 표현식에 정의한 코드를 실행해준다.

영속성 컨텍스트에 엔티티 저장

  • @Entity 애너테이션과 @Id 애너테이션을 추가하면 JPA에서 해당 클래스를 엔티티 클래스로 인식
  • (3) @GeneratedValue 애너테이션은 식별자를 생성해주는 전략을 지정할 때 사용
    • 식별자에 해당하는 멤버 변수에 추가하면 데이터베이스 테이블에서 기본키가 되는 식별자를 자동 설정
  • Member 엔티티클래스의 객체를 JPA의 영속성 컨텍스트에 저장하는 예제
  • JPA의 영속성 컨텍스트는 EntityManager 클래스에 의해 관리, 이 클래스의 객체는 (1) 과 같이 EntityManagerFactory 객체를 Spring으로부터 DI 받을 수 있음.
  • (2) EntityManagerFactorycreateEntityManager() 메서드를 이용해 EntityManager 클래스의 객체를 얻을 수 있음. 객체를 통해서 JPA의 API 메서드 사용 가능
  • (3) 과 같이 persist(member) 메서드 호출하면 영속성 컨텍스트에 member객체의 정보들 저장됨.
  • (4) 영속성 컨텍스트에 member객체가 잘 저장되었는지 find 메서드로 조회
    • 첫 번째 파라미터는 조회 할 엔티티 클래스의 타입
    • 두 번째 파라미터는 조회 할 엔티티 클래스의 식별자 값
      • em.persist(member) 를 호출하면 1차 캐시에 member 객체가 저장, 이 객체는 쓰기 지연 SQL 저장소에 INSERT 쿼리 형태로 등록
      • 실제 테이블에 회원 정보를 저장하지는 않음.

영속성 컨텍스트와 테이블에 엔티티 저장

  • (1) EntityManager 를 통해서Transaction 객체를 얻는다. JPA에서는 이 트랜잭션 객체를 기준으로 데이터베이스의 테이블에 데이터를 저장한다.
  • JPA에서는 (2)와 같이 트랜잭션을 시작하기 위해서 tx.begin() 메서드를 먼저 호출
  • (3) member 객체를 영속성 컨텍스트에 저장
  • (4) tx.commit() 을 호출하는 시점에 컨텍스트에 저장된 member 객체를 데이터베이스의 테이블에 저장한다.
  • (5) em.find(Member.class, 1L) 호출하면 컨텍스트에 저장한 member 객체를 1차 캐시에서 조회
    • 1차 캐시에 member 객체 정보가 있으므로 별도로 테이블에 SELECT 쿼리 전송x
  • (6) em.find(Member.class, 2L) 호출해서 식별자 값이 2L 인 member 객체를 조회
    컨텍스트에 객체가 존재하지 않으므로 (7) 의 결과는 true
    • (6) 에서 컨텍스트에서 2L 객체가 존재하지 않으므로 테이블에 직접 SELECT 쿼리 전송
      • tx.commit() 을 했기 때문에 member 에 대한 INSERT 쿼리가 실행되어 쓰기 지연 SQL 저장소에서 사라진다.

  • SELECT 쿼리 실행됨.

💡

  • em.persist() 호출 시 영속성 컨텍스트의 1차 캐시에 엔티티 클래스 객체 저장, 쓰기 지연 SQL 저장소에 INSERT 쿼리가 등록
  • tx.commit()을 하는 순간 쓰기 지연 SQL저장소에 등록된 INSERT 쿼리 실행, 실행된 쿼리는 저장소에서 제거
  • em.find()를 호출하면 먼저 1차 캐시에서 해당 객체가 있는지 조회, 없으면 테이블에 SELECT 쿼리를 전송해서 조회

쓰기 지연을 통한 영속성 컨텍스트와 테이블에 엔티티 일괄 저장

  • tx.commit() 을 하기 전까지는 SQL 저장소에 등록된 INSERT 쿼리가 실행되지 않음.
    (테이블에 데이터 저장 x)
  • tx.commit() 이 실행된 이후에는 INSERT 쿼리가 모두 실행. 테이블에 데이터 저장됨.

영속성 컨텍스트와 테이블에 엔티티 업데이트

  • (1)에서 member 객체를 영속성 컨텍스트의 1차 캐시에 저장
  • (2) 에서 tx.commit() 호출해서 컨텍스트의 쓰기 지연 SQL 저장소에 등록된 INSERT 쿼리 실행
  • (3) 과 같이 (2)에서 테이블에 저장된 member객체를 영속성 컨텍스트의 1차 캐시에서 조회
    (테이블에서 조회하는것이 아님) 이미 1차캐시에 저장되어있음.
  • (4) setter 메서드로 이메일 변경
  • (5) tx.commit() 을 실행하면 쓰기 지연 SQL 저장소에 등록된 UPDATE 쿼리가 실행된다.
    • UPDATE 쿼리 실행 과정
      영속성 컨텍스트에 엔티티가 저장될 경우에는 그 시점의 상태를 그대로 가지는 스냅샷 생성
      엔티티 값을 setter로 변경 후 커밋을 하면 변경된 엔티티와 스냅셧 비교후 변경된 값이 있으면 UPDATE 쿼리를 등록하고 실행함.

영속성 컨텍스트와 테이블의 엔티티 삭제

  • (1) Member 클래스의 객체를 영속성 컨텍스트의 1차 캐시에 저장
  • (2) 커밋을 호출해서 INSERT 쿼리 실행
  • (3) 영속성 컨텍스트의 1차 캐시에서 조회
  • (4) em.remove(member) 를 통해 1차 캐시에 있는 엔티티 제거 요청
  • (5) 1차 캐시에 있는 엔티티 제거 후 , SQL 저장소에 등록된 DELETE 쿼리 실행
    • tx.commit() 메서드가 호출되면 JPA 내부적으로 em.flush() 메서드가 호출되어 변경 내용을 데이터 베이스에 반영
profile
코린이의 공부 일지

0개의 댓글