course/inflearn

[JPA 프로그래밍 기본편] 영속성 관리

hjkim0502 2022. 8. 30. 16:39

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

  • 눈에 보이지 않는 논리적 개념
  • 엔티티 매니저를 통해 영속성 컨텍스트에 접근
환경 J2SE (기본 자바) J2EE (프레임워크)
엔티티 매니저 : 영속성 컨텍스트 1:1 N:1
  • 엔티티의 생명주기

  • 비영속: 객체를 생성한 상태, Member member = new Member();
  • 영속: 객체를 영속 컨텍스트에 저장한 상태 (JPA가 인식하고 관리해줄 수 있는 상태), em.persist(member);
    • 실제 DB 저장은 트랜잭션 커밋 시에 이루어짐
  • 준영속: 객체를 영속 컨텍스트에서 분리한 상태, em.detach(member);
  • 삭제: 객체를 삭제한 상태, em.remove(member);

2. 영속성 컨텍스트 사용 이점

 

엔티티 조회

  • 1차 캐시 -> 같은 트랜잭션 내에서 이루어진 조회 작업은 1차 캐시에서 불러옴
    • 일반적으로 실제 성능에 유의미한 효과를 주진 않는다 (이런 객체 지향적인 컨셉이 도움됨)

  • 영속 엔티티의 동일성 보장: 자바 컬렉션에서 조회하듯이 1차 캐시에서 읽어온 영속 엔티티의 동일성을 보장해준다
    • == 연산 결과 true 반환

엔티티 등록

  • 트랜잭션 지원 쓰기 지연: 트랜잭션 시작 후 쿼리 작업을 쓰기 지연 SQL 저장소에 쌓아놨다가 커밋 시에 한번에 처리

엔티티 수정

  • 변경 감지 (dirty checking): 트랜잭션 내에서 엔티티를 불러와 수정만해주면 알아서 update 쿼리로 DB에 반영해줌
    • 스냅샷: 최초로 1차 캐시에 저장된 모습을 가지고 있음
    • 오히려 값 변경 후 persist() 메소드 호출하지 않는 것이 맞음

엔티티 삭제

  • 삭제 대상 엔티티 조회 후 remove 메소드를 통해 간편하게 삭제

3. 플러시: 영속성 컨텍스트의 변경내용을 DB에 반영하는 것

  • 우선 더티체킹이 이루어지고, 최종적으로 쓰기 지연 저장소에 쌓인 쿼리들이 DB에 반영
    • rollback이 이루어지면 원복되는 수준으로 반영되며, commit이 이루어지면 완전 확정
  • 트랜잭션의 주기와 영속성 컨텍스트의 주기가 맞게 설계되면 데이터 동기화 관련 문제가 없음
  • 1차 캐시의 정보들에는 변화없음!
  • 직접 호출: em.flush()
  • 자동 호출: 트랜잭션 커밋, JPQL 쿼리 실행 (FlushModeType.AUTO : 기본값(권장) ↔ FlushModeType.COMMIT)
    • FlushModeType.COMMIT: flush가 JPQL 쿼리 실행 시에는 이루어지지 않고, 커밋 시에만 작동
Member member = new Member(200L, "Member");
em.persist(member);

em.flush(); //직접 호출

// 위에서 persist한 member가 이 시점에서는 아직 DB에 없기 때문에 JPQL 실행시 자동 호출
em.createQuery("select m from Member m", Member.class); //자동 호출

tx.commit(); //자동 호출

 

4. 준영속

  • 영속 상태가 될 수 있는 두 가지 상황:
    • 비영속 상태인 객체가 persist()로 영속 상태가 됨
    • 1차 캐시에 없는 객체를 find()로 조회하여 DB에서 불러와 영속 상태가 됨
  • 준영속 상태는 영속 상태에 있는 객체를 영속성 컨텍스트에서 분리하는 것 -> 영속성 컨텍스트 지원 기능 사용 불가
  • em.detach(entity이름): 특정 엔티티만 준영속 상태로 전환
Member member = em.find(Member.class, 1L);
member.setName("hello");

em.detach(member); // 객체에 변동이 생겼지만 변경감지 (dirty checking)이 이루어지지 않음

tx.commit();

// select문은 진행되지만 update는 진행되지 않음
  • em.clear(): 영속성 컨텍스트 초기화 (모든 엔티티가 분리됨)
Member member = em.find(Member.class, 1L);
member.setName("hello");

em.clear();

Member member2 = em.find(Member.class, 1L);

// select 쿼리 두 번 날아감
  • em.close(): 영속성 컨텍스트 종료

출처: 인프런 김영한님 JPA 프로그래밍 - 기본편