[JPA 기본] 영속성 관리
포스트
취소

[JPA 기본] 영속성 관리

영속성 컨텍스트

  • JPA를 이해하는데 가장 중요한 용어
  • “엔티티”를 영구 저장하는 환경이라는 뜻
  • 영속성 컨텍스트는 논리적인 개념이다.
  • 엔티티 매니저를 영속성 컨텍스트에 접근한다.
  • ★★★ 영속성 컨텍스트와 엔티티 매니저는 서로 비슷한 것이지 동일한 건 아니다. ★★★

영속성 컨텍스트의 이점

  • 1차 캐시
  • 동일성 보장
  • 트랜잭션을 지원하는 쓰기 지연
  • 변경 감지
  • 지연 로딩

엔티티의 생명주기

  • 비영속 (new/transient)
    • 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
    • 객체를 생성만 하고 영속성 컨텍스트(엔티티 매니저)에 아무것도 넣지 않은 상태
    • JPLA랑 전여 관계없는 상태
  • 영속 (managed)
    • 영속성 컨텍스트에 관리되는 상태
    • em.persist(객체명);을 통해서 영속성 컨텍스트(엔티티 매니저)에 객체를 저장한 상태
    • 1차 캐시에 올라가서 JPA가 관리하는 상태
  • 준영속 (detached)
    • 영속성 컨텍스트에서 분리된 상태
  • 삭제 (removed)
    • 삭제된 상태
    • 실제 DB 삭제를 요청하는 상태

    Member member = new Member(); //객체를 생성한 상태 (비영속)
    member.setId(3L);
    member.setUsername("memberC");

    System.out.println("=== BEFORE ==="); //출력 순서 1
    em.persist(member); //객체를 저장한 상태 (영속)
    System.out.println("=== AFTER ==="); //출력 순서 2
    
    tx.commit(); //실제 커밋할 때 쿼리 실행, 출력 순서 3

    em.detach(member); //회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태

    em.remove(member); //객체를 삭제한 상태 (삭제) 
    
    //member를 영속성 컨텍스트에서 분리시켰기 때문에 SELECT 쿼리가 발생한다.
    Member findMember = em.find(Member.class, 3L);

1차 캐시

  • 데이터베이스의 한 트랙잭션 안에서만 효과가 있다.
  • 위의 이유때문에 크게 이점을 얻을 수 있는 장점이랄꺼까지는 없지만
    그래도 비즈니스 로직이 복잡할 때는 어느 정도 도움이 된다.
    //객체를 생성한 상태 (비영속)
    Member member = new Member();
    member.setId(4L);
    member.setUsername("memberD");
    em.persist(member);
    tx.commit();

    //1차 캐시에서 가져오기 때문에 SELECT가 발생하지 않는다.
    Member findMember = em.find(Member.class, 4L);
    System.out.println(findMember.getId()); //출력 : 4
    System.out.println(findMember.getUsername()); //출력 : memberD

동일성 보장

  • 영속 엔티티의 동일성 (identity) 보장 => 같은 트랜잭션에 한해서 보장, 1차 캐시의 기능
    Member findMember1 = em.find(Member.class, 5L);
    Member findMember2 = em.find(Member.class, 5L);
    System.out.println(findMember1 == findMember2); //동일성 비교 : true

트랜잭션을 지원하는 쓰기 지연 (transactional write-behind)

    Member member6 = new Member();
    member6.setId(6L);
    member6.setUsername("memberF");
    em.persist(member6); //INSERT 발생 안함
    
    Member member7 = new Member();
    member7.setId(7L);
    member7.setUsername("memberG");
    em.persist(member7); //INSERT 발생 안함
    
    tx.commit(); //INSERT 2건 발생

변경 감지(Dirty Checking)

    Member findMember = em.find(Member.class, 3L); // 영속 엔티티 조회
    findMember.setUsername("memberC-1"); //name 변경
    //em.persist(findMember); => 사용안함
    tx.commit(); //UPDATE 발생

지연 로딩(Lazy Loading)

/*
    추후 작성
*/

준영속 상태

em.detach(entity); //특정 엔티티만 준영속 상태로 전환 

em.clear(); //영속성 컨텍스트를 완전히 초기화 

em.close(); //영속성 컨텍스트를 종료

플러시

  • 정의 : 영속성 컨텍스트 변경내용을 데이터베이스에 반영하는 것
  • 플러시가 발생하면 일어나는 일
    • 변경 감지
    • 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
    • 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송 (등록/수정/삭제)
    • 1차 캐시 유지
  • 플러시 방법
    • em.flush() : 직접 호출
    • 트랜잭션 커밋 : 자동 호출
    • JPQL 쿼리 실행 : 자동 호출
  • 플러시 특징
    • 영속성 컨텍스트를 비우지 않음
    • 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화
    • 트랜잭션이라는 작업 단위가 중요 → 커밋 직전에만 동기화하면 된다.
  • 플러시 옵션
    • 사용법 : em.setFlushMode(FlushModeType.COMMIT)
    • FlushModeType.AUTO (기본값) : 커밋이나 쿼리를 실행할 때 플러시
    • FlushModeType.COMMIT : 커밋할 때만 플러시 (크게 이점 없음)

출처

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.