[JPA 프로그래밍 - 기본편] 영속성 관리 - 내부 동작 방식

지현·2022년 2월 3일
0

JPA

목록 보기
3/12

엔티티 매니저 팩토리를 통해서 고객의 요청이 오면 엔티티 매니저를 생성
엔티티 매니저는 내부적으로 데이터베이스 커넥션을 사용하여 디비를 사용

영속성 컨텍스트

  • 엔티티를 영구 저장하는 환경 EntityManager.persist(entity);
  • persist 메서드는 엔티티를 디비에 저장하는것이 아니라 영속성 컨텍스트에 저장
  • 엔티티 매니저를 통해서 영속성 컨텍스트에 접근

엔티티의 생명주기

  • 비영속 (new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
//객체를 생성한 상태(비영속), JPA와 전혀 관계 없는 상태
Member member = new Member(); 
member.setId("member1"); 
member.setUsername("회원1");
  • 영속 (managed) : 영속성 컨텍스트에 관리되는 상태
//객체를 저장한 상태(영속)
em.persist(member);
  • 준영속 (detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태 
em.detach(member); 
  • 삭제 (removed) : 삭제된 상태
//디비에 삭제를 요청한 상태
//객체를 삭제한 상태(삭제) 
em.remove(member);

영속성 컨텍스트의 이점

  1. 1차 캐시
    • em.persist로 엔티티를 영속하면 영속성 컨텍스트 내부에 있는 1차 캐시에 엔티티를 저장해둠
    • em.find로 조회할 때 먼저 1차 캐시에서 찾음, 없으면 DB에서 조회하고 1차 캐시에 저장후 반환
    • 큰 도움은 되지 않음 (고객의 요청이 들어오고 끝나면 영속성 컨텍스트를 지워서 1차 캐시도 다 날라감, 동일한 트랜잭션 안에서만 사용됨)
  2. 동일성(identity) 보장
    • 동일한 트랜잭션에서 조회한 엔티티는 같음을 보장
    • 1차 캐시가 있기 때문에 가능
    Member a = em.find(Member.class, "member1"); 
    Member b = em.find(Member.class, "member1");
    System.out.println(a == b); //동일성 비교 true
  3. 트랜잭션을 지원하는 쓰기 지연 (transactional write-behind)
    //엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
    transaction.begin(); // [트랜잭션] 시작
    em.persist(memberA);
    em.persist(memberB);
    //여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
    //커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
    transaction.commit(); // [트랜잭션] 커밋
    • em.persist(memberA)를 하면 1차 캐시에 저장하고, 엔티티를 분석해서 INSERT SQL을 생성후 쓰기 지연 SQL 저장소에 쌓아둠
    • transaction.commit() 을 하면 쓰기 지연 SQL 저장소에 있던 것들이 flush가 되면서 실제 DB에 commit 됨
  4. 변경 감지(Dirty Checking)
    • 값을 바꾸면 트랜잭션이 커밋되는 시점에 알아서 DB에 변경을 반영해줌
    // 영속 엔티티 조회
    Member memberA = em.find(Member.class, "memberA");
    // 영속 엔티티 데이터 수정
    memberA.setUsername("hi");
    memberA.setAge(10);
    • transaction.commit() 할 때 내부적으로 flush가 호출되고 엔티티와 스냅샷을 비교(1차 캐시 내부에는 @ID(PK), 엔티티, 스냅샷(최초시점의 상태를 넣어둠)이 저장)
    • 비교해보고 변경 된 것이 있으면 UPDATE SQL을 쓰기 지연 SQL 저장소에 만들어둠
    • UPDATE 쿼리를 DB에 반영하고 커밋
    //삭제 대상 엔티티 조회 
    Member memberA = em.find(Member.class, “memberA");
    em.remove(memberA); //엔티티 삭제
    //DELETE 쿼리가 트랜잭션 커밋 시점에 나가게 됨
  5. 지연 로딩(Lazy Loading)

플러시

  • 영속성 컨텍스트의 변경내용을 데이터베이스에 반영
  • 영속성 컨텍스트를 비우지 않음
  • 트랜잭션이라는 작업 단위가 중요 -> 커밋 직전에만 동기화 하면 됨
  • 트랜잭션을 커밋하거나, JPQL 쿼리를 실행할 때 자동으로 플러시가 되고, 직접 호출할 수도 있음

준영속 상태

  • 영속 -> 준영속
    • 영속상태가 되는 case > 1차 캐시에 올라가는 상태
      • em.persist()
      • em.find()
  • 영속 상태의 엔티티가 영속성 컨텍스트에서 분리 (detached)
  • 영속성 컨텍스트가 제공하는 기능을 사용 못함

준영속 상태로 만드는 방법

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


출처
[인프런] 자바 ORM 표준 JPA 프로그래밍 - 기본편

0개의 댓글

관련 채용 정보