JPA스터디 - 2

한상우·2022년 11월 13일
0

JPA

목록 보기
2/7

11/12

장소: 당산역 스터디위드 스터디룸
시간: 10:00 ~ 12:00

3장

엔티티 매니저 팩토리, 엔티티 매니저

  • 엔티티 매니저 팩토리: 엔티티 매니저를 만드는 공장

  • 엔티티 매니저: 엔티티를 저장하고, 수정하고, 삭제하고, 조회하는 등 엔티티와 관련된 모든일을 처리한다

  • 엔티티 매니저 팩토리는 여러 스레드가 동시에 접근해도 안전하지만 엔티티 매니저는
    여러 스레드가 동시에 접근하면 동시성 문제가 발생하여 스레드 간에 공유해서는 안된다.

  • 엔티티 매니저는 DB 연결이 꼭 필요한 시점까지 커넥션을 얻지 않는다 (트랜잭션을 시작할 때)

영속성 컨텍스트

  • 엔티티 매니저로 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리
  • ex) persist(member)를 하게 되면 member 엔티티를 영속성 컨텍스트에 저장

엔티티 생명주기

  • 비영속 상태: 영속성 컨텍스트와 전혀 관계가 없음
    • 순수한 객체 상태
  • 영속 상태: 영속성 컨텍스트에 저장된 상태
    • 영속성 컨텍스트가 관리하는 엔티티
  • 준영속: 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 삭제: 영속성 컨텍스트와 DB에서 엔티티를 삭제

영속성 컨텍스트의 특징

  • 영속 상태는 식별자 값이 반드시 있어야 함
  • flush 하는 순간 엔티티가 DB에 반영된다

영속성 컨텍스트 장점

  1. 1차 캐시

    • 영속성 컨텍스트는 내부에 캐시를 가지고 있음
    • Map이 하나 있는데 키는 @Id로 매핑한 식별자이고 값은 엔티티 인스턴스
    • em.find("member1")을 해주면 키값을 기준으로 1차 캐시에서 먼저 엔티티를 조회
    • 만약 1차 캐시에 존재하지 않는다면 DB에서 조회 후 엔티티를 생성하여 1차 캐시에 저장하고 영속 상태 엔티티 반환
    • 1차 캐시에서 값을 반환해오기 때문에 엔티티의 동일성을 보장해준다
  2. 쓰기 지연

    • 엔티티 매니저는 트랜젝션을 커밋하기 직전까지 내부 쿼리 저장소에 SQL을 모아둠, 커밋할 때 모아둔 쿼리를 DB에 보냄
    • 트랜젝션을 커밋하면, 엔티티 매니저는 영속성 컨텍스트를 플러시 한다
    • 여기서 플러시란 DB와 영속성 컨텍스트의 변경 사항을 동기화 시키는 것으로, 쓰기 지연 SQL에 모인 쿼리를 DB에 보낸다.
  3. 변경 감지

  • 변경감지 (dirty checking)을 통해 엔티티의 변경 사항을 DB에 자동으로 반영
  • 변경 사항을 어떻게 아느냐 하면, 엔티티를 영속성 컨텍스트에 보관할 떄 스냅샷이라고 최초 상태를 복사해 저장한다, 플러시 시점에 스냅샷과 엔티티를 비교.
  • JPA는 엔티티의 모든 필드를 업데이트 하는게 기본 전략인데,
    • 수정 쿼리가 항상 같아 애플리케이션 로딩 시점에 수정 쿼리를 미리 생성해두고 재사용 가능하고
    • DB에 동일한 쿼리를 보내면 DB는 이전에 온 쿼리를 재사용할 수 있다

플러시

  • 영속성 컨텍스트 변경 내용을 DB에 반영하는 것
  • 플러시를 실행하면, 변경 감지가 동작하여 수정된 엔티티를 찾아 수정 쿼리를 만들고 이를 지연 SQL저장소에 등록 쓰기 지연 SQL 저장소의 쿼리를 DB에 전송한다
  • 플러시 하는 방법
    1. 직접 호출 (em.flush)
    2. 커밋시 플러시 자동 호출
    3. JPQL 쿼리 실행 시 플러시가 자동 호출
      • 영속성 컨텍스트에만 반영된 내용이 있고 DB에는 반영되지 않은 내용이 있다 했을 때 JPQL로 쿼리를 실행하면, 변경내용이 포함되지 않는다. 때문에 쿼리 실행 직전에 플러시를 해준다

준영속

  • 준영속 상태로 만드는 방법
    1. em.detach(entity) : 특정 엔티티만 준영속 상태로
    2. em.close(): 영속성 컨텍스트 초기화
    3. em.close(): 영속성 컨텍스트 종료
  • 특징
    • 거의 비영속 상태에 가까움
    • 식별자 값을 가지고 있음
    • 지연로딩을 할 수 없음 (8장에서 다룬다..)

병합

  • 준영속 상태 엔티티를 다시 영속 상태로 변경

스터디

  • 위치: 당산역 스터디룸위드
  • 시간: 11/12 10:00 ~ 12:00
  • 내 질문: 쓰기 지연을 하는 이유가 있을까??? 이에 대한 이점이 있을까??
처음 이 질문에 대한 답변으로
insert를 계속 하다가 중간에 뻑이 났을 경우 문제가 발생하니 쓰기 지연을 해야하지 않을까요?

라는 답변을 받았지만, 커밋을 해주지 않으면 insert를 실행한 결과값이 DB에 반영되지 않으니까
쓰기 지연을 쓰는 이유가 되는지 모르겠다고 여쭤봤다.

결국 같이 답을 찾아봤는데,
JPA를 사용하지 않고, 직접 SQL문을 다루면 update문을 실행할 때 그 업데이트에 대한 행에 DB 락이 걸리게 되고 이후 커밋을 하게 되면 그때 락이 풀린다고 한다. 하지만 JPA를 사용하게 되면, 커밋을 해야 플러시를 통해 DB에 쿼리문을 보내니까 락이 걸리는 시간을 최소화 할 수 있다고 한다.
  • 커밋과 플러시의 차이??

  • 찾아보니 커밋과 플러시 둘다 DB에 변경 내용에 대한 데이터를 넣어주는 것인데, 커밋은 인덱스까지 다뤄주지만, 플러시는 아니라고 한다.
    인덱스는 추가적인 쓰기 작업과 저장 공간을 활용하여 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조

  • 비용이 든다는 말이 어떤건가요??

  • 월요일날 질문하고 다시 정리하세요!


4장

@Entity

  • JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 어노테이션을 붙여줘야 한다
  • 위 어노테이션이 붙으면 기본 생성자가 필수다

@Table

  • 엔티티와 매핑할 테이블을 지정한다, 생략하면 Entity 이름을 테이블 이름으로 사용한다

기본 키 매핑

  • JPA가 제공하는 DB 기본 키 생성 전략
  1. 직접 할당

    • setId 를 통해 기본키 직접 할당
  2. 자동 생성

    • IDENTITY: 기본 키 생성을 DB에 위임

      • ID 컬럼을 비워두고 DB에 값을 저장하면 DB 가 순서대로 값을 채워줌
      • DB에 값을 저장하고 나서야 기본키 값을 구할 수 있음
      • 참고로 영속 상태가 되려면 식별자 값이 반드시 필요하기에 이 전략에서 em.persist()를 호출하면 INSERT SQL문이 바로 DB에 전달.
    • SEQUENCE: DB 시퀀스를 사용해서 기본키 할당

      • 오라클, Postgresql, H2 에서 사용 가능
      • 시퀀스란 유일한 값을 순서대로 생성하는 특별한 DB 오브젝트
      • em.persist()를 호출할 때 먼저 DB 시퀀스를 통해 식별자를 조회, 이후 식별자를 엔티티에 할당 하고 영속성 컨텍스트에 저장
    • TABLE: 키 생성 테이블을 사용

      • 키 생성 전용 테이블을 하나 만들어.
      • 테이블을 사용하는 것이기에 모든 데이터베이스에 적용 가능하다
    • AUTO

      @Id
      @GeneratedValue // 기본값이 AUTO다
      private Long id
      • auto 는 선택한 DB 방언에 따라 오라클 선택하면 SEQUENCE를 MYSQL을 선택하면 IDENTITY를 사용한다
      • DB를 변경해도 코드를 수정할 필요가 없음

추가

  • @Enumerated

    • enum 타입을 매핑할 때 사용
    • 기본값이 EnumType.ORDINAL인데 enum에 정의된 순서대로 정수값이 DB에 저장된다
    • 하지만 이는 추후 enum 이 변경되었을 때 문제가 발생할 수 있으므로 EnumType.STRING을 사용해야 한다. (실제 enum 값으로 DB에 저장)
  • @Transient

    • DB에 저장하거나 조회하지는 않지만, 객체에 임시로 값을 보관하고 싶을 떄 사용
    • 많이 안쓰이는 어노테이션이라 생각했는데, 스터디원분중 현업에 계시는 분은 많이 사용하고 있으시다.!!
profile
안녕하세요 ^^

0개의 댓글