[SpringBoot] 영속성 관리

·2023년 9월 9일

영속성 컨텍스트

JPA에서 가장 중요한 2가지를 꼽으라면 다음과 같다.

  • 객체와 관계형 데이터베이스 매핑하기 (Object Relational Mapping)
  • 영속성 컨텍스트

    EntityManagerFactory를 통해 고객의 요청이 들어올 때마다 EntityManager를 생성하게 된다. 이렇게 생성된 EntityManager는 내부적으로 데이터베이스 커넥션을 사용해서 DB를 사용하게 된다.

영속성 컨텍스트란 JPA를 이해하는데 가장 중요한 용어로 “엔티티를 영구 저장하는 환경” 이라는 뜻으로 EntityManager.persist(entity); 를 사용하여 저장하면 DB에 바로 저장하는것 처럼 보이지만 사실은 EntityManager에 영속시기는 것이다. 따라서 영속성 컨텍스트는 논리적인 개념이라 눈에 보이지 않고, 엔티티 매니저를 통해서 접근을 할 수 있다.

엔티티의 생명주기

  • 비영속 (new/transient)
    • 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
  • 영속 (managed)
    • 영속성 컨텍스트에 관리되는 상태
  • 준영속 (detached)
    • 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 삭제 (removed)
    • 삭제된 상태



준영속 —> em.detach(member);

삭제 —> em.remove(member);

영속성 컨텍스트의 이점

  • 1차 캐시를 사용하여 DB에 접근하지 않아도 데이터를 얻어올 수 있다.
  • 동일성(identity) 보장
  • 트랜잭션을 지원하는 쓰기 지연
  • 변경 감지(Dirty Checking)
  • 지연 로딩(Lazy Loading)

em.persist(member); 를 실행하게 되면 1차 캐시에 저장이 된다.

그 후 Member findMember = em.find(Member.class, “member1”); 을 실행하면 DB에 접근해서 Member를 조회하는게 아니라 1차 캐시에서 조회를 해 오게 된다. 만약 1차 캐시에 정보가 없을 경우, DB를 조회하여 가져오고 1차 캐시에 저장한 후 반환 하게 된다.

다음 예시와 같이 영속 엔티티는 동일성이 보장된다.

ex)

Member a = em.find(Member.class, “member1”);

Member b = em.find(Member.class, “member2”);

System.out.println(a == b); //true

트랜잭션을 지원하는 쓰기 지연


em.persist(memberA);
em.persist(memberB); 를 하게 되면 memberA와 B는 1차캐시에 들어가는 동시에 INSERT SQL이 생성되어 “쓰기 지연 SQL 저장소”에 저장된다. 그 후 transaction.commit(); 순간에 이 쿼리들이 DB로 날라가게 되고, DB에 커밋이 된다.

또한 1차 캐시에는 엔티티가 처음 1차캐시에 저장될 때, 스냅샷을 만들어 읽어 왔던 최초 모습을 저장한다. 이를 통해 데이터를 수정할 때, em.update(member)와 같은 코드가 있지 않아도 알아서 스냅샷과 비교해 변동이 있으면 마찬가지로 쓰기 지연 저장소에 UPDATE 쿼리를 저장한다.

플러시

플러시란 영속성 컨텍스트의 변경내용을 데이터베이스에 반영하는 것이다.

변경을 감지하면, 수정된 엔티티 쓰기 지연 SQL 저장소에 등록을 하고 등록, 수정, 삭제 쿼리를 데이터 베이스에 전송을 하게 된다. 이때 플러시 후 커밋을 하게 된다.

영속성 컨텍스트를 플러시 하는 방법에는 3가지 방법이 있다.

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

쿼리 실행 시 자동 호출이 되는 이유는 그렇게 하지 않으면, 데이터를 넣은 다음 바로 조회를 하면 1차캐시에만 있고 DB에는 없어서 읽어오지 못하기 때문이다.

또한 플러시 모드 옵션을 사용하여 플러시 시점을 조절할 수 있다.
—> em.setFlushMode(FlushModeType.COMMIT)

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

플러시는 영속성 컨텍스트를 비우지 않는다. 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화하며 트랜잭션이라는 작업 단위가 중요하다. (커밋 직전에만 동기화 하면 된다.)

준영속 상태란 영속 상태의 엔티티가 영속성 컨텍스트에서 분리가된 상태이다. 준영속 상태가 되면 영속성 컨텍스트가 제공하는 기능을 사용하지 못하게 된다.

준영속 상태로 만드는 방법

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

0개의 댓글