[JPA] 3. 영속성 관리

지니🧸·2023년 2월 8일
0

Spring Boot & JPA

목록 보기
10/35

본 문서는 인프런의 자바 ORM 표준 JPA 프로그래밍 - 기본편 (김영한) 강의를 공부하며 작성한 개인 노트입니다.

JPA에서 가장 중요한 2가지 - 객체와 관계형 데이터베이스 매핑 (ORM) & 영속성 컨텍스트

💬 영속성 컨텍스트

Entity Manager Factory & Entity Manager

Entity Manager Factory는 고객의 요청마다 새로운 Entity Manager를 생성함
Entity Manager는 내부적 커넥션으로 디비 사용

영속성 컨텍스트 (PersistenceContext)

영속성 컨텍스트: 엔티티를 영구 저장하는 환경

  • EntityManager.persist(entity);
    • 디비에 저장하는 것이 아닌, 영속성 컨텍스트에 저장하는 것
  • 영속성 컨텍스트는 논리적 개념.
    • entity manager를 통해 영속성 컨텍스트에 접근
      • entity manager를 생성하면 1:1로 영속성 컨텍스트가 생성됨
  • 이점
    1. 1차 캐시
    • 1차 캐시에서 조회: 조회 요청이 들어오면 영속성 컨텍스트는 1차 캐시에서 찾아서 있으면 바로 반환
      - em.find(Member.class, "member1");
      - 1차 캐시에 없으면 디비에서 조회, 1차 캐시에 저장하여 반환
      • 하지만 EntityManager는 데이터베이스 transaction 단위로 주로 만듬 > 비즈니스가 끝나면 영속성 컨텍스트가 지워져서 캐시도 날라감
    1. 영속 엔티티의 동일성 보장, identity
    • 1차 캐시 덕에 반복 가능 읽기(repeatable read) 트랜잭션 격리 수준을 앱 차원에서 제공
      Member a = em.find(Member.class, "member1");
      Member b = em.find(Member.class, "member1");
      System.out.println(a==b); // true
    1. 트랜잭션을 지원하는 쓰기 지연, transactional write-behind
    • 커밋하는 순간 데이터베이스에 INSERT SQL을 보냄
      • 그전에는 (em.persist에도) INSERT SQL을 디비에 보내지 않음
      • em.persist마다 INSERT SQL을 생성하여쓰기 지연 SQL 저장소에 저장함
    • transaction.commit(); - 쓰기지연 SQL 저장소의 SQL문이 flush되면서 커밋
    1. 변경 감지, Dirty checking > 변경시에는 em.persist() 사용 X
    • 트랜잭션 커밋 시점에 영속 컨텍스트 내부적으로 flush 실행
      - 1차 캐시 안에서 엔티티와 스냅샷 비교
      • 스냅샷: 값을 읽어온 최초 시점의 값을 저장
    • 엔티티 & 스냅샷을 모두 비교해서 바뀐 값이 있으면 UPDATE 쿼리를 생성하여 쓰기 지연 SQL 저장소에 저장
      - 업데이트된 쿼리는 디비에 반영
    • 커밋
    1. 지연 로딩, Lazy loading

엔티티의 생명주기

  • 비영속, new/transient: 영속성 컨텍스트와 관계 없음
    • 새로운 상태
    • 최초에 객체를 생성한 상태
  • 영속, managed: 영속성 컨텍스트에 관리되는 상태
    • EntityManager.persist(entity) 이후
    • 객체가 영속성 컨텍스트에 들어감
    • 디비에 바로 저장되지는 않음
      • transaction commit에 저장
  • 준영속, detached: 영속성 컨텍스트에 저장되었다가 분리된 상태
    • em.detach(member);
    • 영속성 컨텍스트에서 삭제
  • 삭제, removed: 삭제된 상태
    • em.remove(member);
    • 디비 삭제 요청

💊 플러시

플러시: 영속성 컨텍스트의 변경내용을 디비에 반영 (동기화)

  • 트랜잭션 커밋 시 일어남
  • 영속성 컨텍스트를 비우지 않음
  • 작업 단위 > 트랜잭션: 커밋 직전에만 동기화하면 됨

플러시 발생

  1. 변경 감지
  2. 수정된 엔티티 > 쓰기 지연 SQL 저장소에 등록
  3. 쓰기 지연 저장소의 등록/수정/삭제 쿼리를 디비에 전송

플러시하는 방법

  • em.flush() - 직접 호출
  • 트랜잭션 커밋, transaction.commit() - 플러시 자동 호출
  • JPQL 쿼리 실행 - 플러시 자동 호출

플러시 모드 옵션

em.setFlushMode(FlushModeType.COMMIT)
  • FlushModeType.AUTO - 커밋이나 쿼리를 실행할 때 플러시
    • 기본값
  • FlushModeType.COMMIT - 커밋할 때만 플러시

🔓 준영속 상태

준영속

  • 영속 > 준영속
  • 영속 상태의 엔티티가 영속성 컨텍스트에서 분리 (detached)
  • 영속성 컨텍스트 기능 사용 X

준영속 상태로 만드는 방법

  • em.detach(entity) - 특정 엔티티만 준영속 상태로 전환
  • em.clear() - 영속성 컨텍스트 초기화
  • em.close() - 영속성 컨텍스트 종료
profile
우당탕탕

0개의 댓글