영속성 관리

Jaca·2021년 8월 12일
0

JPA에서 가장 중요한 두가지

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

영속성 컨텍스트

JPA를 이해하는데 가장 중요한 용어로서 엔티티를 영구 저장하는 환경이다.
영속성 컨텍스트는 논리적인 개념이며, EntityManagerFactory 를 통해 생성한 EntityManager 를 통해 접근이 가능하다.

스프링 프레임워크 같은 컨테이너 환경에서 EntityManager 는 영속성 컨텍스트와 1:N 으로 매칭된다.

Entity의 생명 주기

  • 비영속 (new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태

  • 영속 (managed) : 영속성 컨텍스트에 관리되는 상태

  • 준영속 (detached) :영속성 컨텍스트에 저장되었다가 분리된 상태

  • 삭제 (removed) : 삭제된 상태

예제 테이블

JPA CRUD API

예제를 들어가기 전에 JPA에서 제공하는 CRUD API에 대해 간략히 알아보자

  • Insert : persist
  • Select : find
  • Delete : delete
  • Update : 아래에서 알아보자.

비영속

//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId(1L);
member.setName("User1");

현재 객체를 만들기만 하고 영속성 컨테이너에 올리지 않아 존재만하는 상태이다.

영속

//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername(“회원1);

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

 //객체를 저장한 상태(영속)
em.persist(member);

EntityManager.persist() 메소드를 통해 영속성 컨테이너에 올릴 수 있다.

준영속, 삭제

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

영속성 컨텍스트의 이점

  • 1차 캐시
  • 동일성(identity) 보장
  • 트랜잭션을 지원하는 쓰기 지연 (transactional write-behind)
  • 변경 감지(Dirty Checking)
  • 지연 로딩(Lazy Loading)

엔티티 조회, 1차 캐시

엔티티를 영속성 컨테이너에 영속 시키게 되면 이 정보는 1차 캐시에 저장되어 이후에 동일한 정보를 요청시 DB 연산을 거치지 않고 1차 캐시에서 뽑아서 준다.

insert 문 후, select문이 호출되지 않은 모습. 1차 캐시에서 바로 꺼내 왔기 때문.

DB에서 조회

클래스를 재실행 시키면 DB에 저장된 정보는 남지만, 영속성 컨테이너는 EntityManager 와 매칭되어 있기 때문에, 재실행시 EntityManager가 새로 만들어지며 1차 캐시도 갱신된다.

기존에 저장해두었던 Id = 1L의 데이터를 두번 불러서 같은 객체인지 확인해보았다.
결과는 select문이 실행되고 그 데이터는 1차 캐시에 저장되어 select문이 한번만 실행되었고, 같은 객체임을 알 수 있다.

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

데이터베이스를 공부하며 트랜잭션은 commit을 기준으로 연산을 저장하며 오류 시 rollback 한다는 점을 이미 알고있다.

em.persist(memberA); 
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋

주석처럼 .persist() 를 통해 영속성 컨테이너에 올려도 이는 DB에 저장됬다는 의미는 아니다.
컨테이너 내의 쓰기 지연 저장소에 저장되어 commit 이나 기타 상황을 기다린다.

엔티티 수정, 변경 감지

JPA CRUD API중 update문에 해당하는 메소드가 존재하지 않는다.

물론 아래 더 있긴한데.. 편집 실력 부족...

그렇다면 JPA에서 어떻게 update를 하게 될까?

기존에 저장되있던 Member(1L, User1) 의 데이터를 찾아와
.setName("Change Name") 으로 이름만 바꿔주고 아무런 작업을 하지 않았으나, 콘솔에 update문이 실행되었다.

웹 콘솔에서 본 DB에도 반영된 모습.

이것이 어떻게 가능할까?

영속성 컨텍스트가 최초로 DB에서 데이터를 불러오는 시점을 스냅샷으로 저장한다.
이후 commit 이 일어날 때 flush 가 일어나는데 이 때, 스냅샷의 정보와 비교하여 변경점을 자동으로 적용시켜 준다.

플러쉬

flush 가 어떤 놈일까?
flush 를 간단히 말하자면 변경 사항을 감지하는 놈이다.
flush 가 호출되면 영속성 컨텍스트의 쓰기 지연 저장소에 저장된 내용을 DB에 반영시킨다. (CRUD 메소드들이 쌓여있다가 반영됨) 영속성 컨텍스트가 비워지진 않는다.
쉽게 얘기해서 영속성 컨텍스트의 변경 사항들과 DB의 상태를 맞추는 작업이다.

영속성 컨텍스트를 플러쉬 하는 방법

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

flush() 를 자동으로 호출할수도 있지만 수동으로 해줘야 할 때가 있다.
예를들면.. 저장하고자하는 정보를 commit 전에 불러 오고자 한다던가...
외에 JPQL 쿼리나 부가 다른 경우도 추후에 더 학습한다고 한다.

profile
I am me

0개의 댓글