computer_study

[JPA] 03. 영속성 관리 본문

스터디/자바 ORM표준 JPA 프로그래밍

[JPA] 03. 영속성 관리

knowable 2022. 6. 29. 23:02

1. 엔티티 매니저 팩토리와 엔티티 매니저

DB를 하나만 사용하는 어플이라면 EntityManager Factory를 하나만 생성 후 EntityManager를 생성한다.(비용이 거의 안든다.)

EntityManager은 DB와 커넥션을 하지 않다가 필요한 시점에 (ex. 트랜잭션 시작 시) 커넥션을 획득한다.

 

2. 영속성 컨텍스트란?

(persistence context) 엔티티를 영구 저장하는 환경

 

EntityManager로 Entity를 저장하거나 조회하면 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.

ex) em.persist(member)

-> persist() 메소드는 엔티티 매니저를 사용해서 회원 엔티티를 영속성 컨텍스트에 저장한다.

 

3. 엔티티의 생명주기

엔티티의 4가지 상태

  • 비영속
    • 영속성 컨텍스트와 관련이 없는 상태
    • 객체를 생성했으나 순수한 객체 상태이고 저장하지 않은 상태. -> 영속성 컨텍스트나 DB와는 관련이 없다.
  • 영속
    • 영속성 컨텍스트에 저장된 상태
    • 영속성 컨텍스트가 관리하는 엔티티를 영속 상태라 한다.
  • 준영속
    • 영속성 컨텍스트에 저장되었다가 분리된 상태
    • 관리하던 영속 상태의 엔티티를 관리하지 않는 상태.
    • em.detach() : 준영속으로 만든다 / em.close() : 영속성 켄텍스트를 닫늗다 / em.clear() : 영속성 컨텍스트를 초기화한다. /  모두 엔티티가 준영속 상태가 된다.
  • 삭제
    • 삭제된 상태
    • em.remove(member)

 

4. 영속성 컨텍스트의 특징

조회

  • 영속성 컨텍스트는 내부에 캐시를 가지고 있기에 1차 캐시 기능을 하는 장점이 있다.(엔티티들이 Map처럼 저장된다.)
  • 1차 캐시의 키는 식별자 값, 식별자 값은 DB Primary Key와 매핑되어있다.
  • em.find() 호출 시 1차 캐시에서 조회 후 없다면 DB조회한다.
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");

// a == b 했을 시 동일성은 참이라 나온다.
// 1차 캐시에 있는 같은 값을 가져오기 때문에 같은 인스턴스이다

 

등록

  • 영속성 컨텍스트에 쓰기 지연 저장소가 있기 때문에, 트랜잭션을 커밋하기 전에 DB에 엔티티를 저장하지 않고 SQL을 쌓아둘 수 있다.
  • 1차 캐시와 저장소에 우선 저장 후 flush과정을 거친 뒤 마지막에 커밋한다.
  • flush   v.s  commit
    • flush는 쿼리는 전송하는 역할
    • commit은 내부적으로 flush 수행한 뒤 트랜잭션을 끝내는 역할
    • flush로 전송된 쿼리는 rollback할 수 있지만 commit은 트랜잭션이 끝났기에 rollback할 수 없다.
    • 참고

 

수정

  • JPA로 엔티티 수정 시 단순히 엔티티를 조회해서 데이터만 변경하면 된다. (변경사항을 자동으로 감지해서 반영한다.
  • 영속성 컨텍스트를 사용하기에 가능하다.
    • JPA는 엔티티를 컨텍스트에 보관할 때 최초 상태를 복사해서 저장해둔다. (스냅샷)
    • 플러시 시점에 위 스냅샷과 엔티티를 비교해서 변경된 엔티티를 찾는다.
  • 변경감지는 영속성 컨텍스트가 관리하는 영속 상태의 엔티티에만 적용된다.
    • 비영속성, 준영속성 상태의 엔티티는 값을 변경해도 DB에 반영이 되지 않는다.
  • 수정 시 엔티티의 모든 필드를 업데이트 한다.
    • 수정쿼리를 미리 생성해두고 재사용할 수 있다.(수정 쿼리가 항상 같아서)
    • DB에 그 쿼리를 보내면 DB는 한 번 파싱된 쿼리를 재사용할 수 있다.
    • 수정된 데이터만 업데이트할 수 있는 기능도 있다. (하이버네이트 확장 기능 사용)

 

삭제

  • 삭제를 위해선 우선 조회 후 삭제를 해야한다. (삭제 과정은, SQL 저장 -> 플러시 -> 커밋 과정 똑같다.)
  • em.remove(memberA) 호출하는 순간 memberA는 영속성 컨텍스트에서 제거된다.
  • 삭제된 엔티티는 재사용하지 말고 가비지 컬렉션의 대상이 되도록 두는 것이 좋다.

 

5. 플러시

영속성 컨텍스트의 변경 내용을 DB에 반영한다.

(영속성 컨텍스트에 보관된 엔티티를 지우는 것이 아니라 반영하는 것)

 

플러시 실행 시

  • 영속성 컨텍스트에 있는 모든 엩티티를 스냅샷과 비교. 수정된 엔티티를 찾는다.
  • 수정된 것이 있으면 수정 쿼리를 만들어 지연 SQL 저장소에 등록한다.
  • 쓰기 지연 SQL 저장소의 쿼리를 DB에 전송한다.

플러시 실행 방법

  • em.flush() 직접 호출
    • 테스트나 다른 프레임워크와 JPA를 함께 사용할 때 제외하곤 거의 사용하지 않는다.
  • 트랜잭션 커밋 시 플러시 자동 호출
    • 커밋 전에 꼭 플러시를 호출해서 변경 내용을 DB에 반영해야 한다.
  • JPQL 쿼리 실행 시 플러시 자동 호출

플러시 모드 옵션

엔티티 매니저에 플러시 모드를 직접 지정할 수 있다. (javax.persistence.FlushModeType 사용)

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

 

6. 준영속

준영속 상태는 영속성 컨텍스트가 제공하는 기능을 사용할 수 없다.

 

  • detach()
    • 엔티티를 준영속 상태로 만든다.
    • 명령어 입력 시 1) 1차 캐시를 제거하고 2) 관련 SQL을 제거한다.
  • clear()
    • 영속성 컨텍스트를 초기화해서, 해당 영속성 컨텍스트의 모은 엔티티를 준영속 상태로 만든다.
    • 엔티티 하나의 캐시, SQL을 제거하는 것이 아니라 캐시와 SQL저장소를 비워버린다.
  • close()
    • 종료 시 관리하던 엔티티가 모두 준영속 상태가 된다.

 

준영속 상태의 특징

  • 비영속 상태에 가깝다
    • 영속성 컨텍스트가 제공하는 어떠한 기능도 동작하지 않는다.
  • 식별자 값을 가지고 있다.
    • 비영속 -> 식별자가 없을 수도 있지만, 준영속은 한 번 영속상태였으므로 반드시 식별자가 있다.
  • 지연 로딩을 할 수 없다.

 

병합: merge()

준영속 상태를 다시 영속상태로 변경할 수 있다.

merge()는 준영속 상태의 엔티티를 받아 새로운 영속 상태의 엔티티를 반환한다.

  1. merge() 실행
  2. 파라미터로 넘어온 준영속 엔티티의 식별자 값으로 1차 캐시에서 엔티티 조회
  3. 엔티티가 없으면 DB에서 조회 후 1차 캐시에 저장
  4. 조회한 영속 엔티티에 값을 채워넣는다.
  5. 반환

비영속 병합

  • 비영속 상태도 영속 상태로 만들 수 있다.
  • 엔티티의 식별자 값으로 영속성 컨텍스트를 조회하는데, 1차 캐시 -> DB 순으로 조회 후 없다면 생성 후 병합한다.

 

 

 

'스터디 > 자바 ORM표준 JPA 프로그래밍' 카테고리의 다른 글

[JPA] 05. 연관관계 매핑 기초  (0) 2022.07.25
[JPA] 04. 엔티티 매핑  (0) 2022.07.11
[JPA] 02. JPA 시작  (0) 2022.06.29
[JPA] 01. JPA 소개  (0) 2022.06.18
[JPA] 00.스터디 개요  (0) 2022.06.18
Comments