대충 넘어가지 않는 습관을 위한 기록

JPA 기록 - 영속성 관리 : 내부 동작 방식

uhyvn 2024. 4. 2. 22:23

김영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 을 보고 기록한 글입니다.

 


 

 

요청이 오고 EntityManagerFactory를 통해 EntityManager를 생성하고,

내부적으로 데이터베이스 커넥션을 사용해서 DB를 사용한다..!

 

 


 

 

영속성 컨텍스트란?

"엔티티를 영구 저장하는 환경"이라는 뜻

 

EntityManager.persist(entity) => DB에 저장한다는게 아니라 영속성 컨텍스트라는 곳에 저장하는 것

 

영속성 컨텍스트는 논리적인 개념이다.

눈에 보이지 않는다.

엔티티 매니저를 통해서 영속성 컨텍스트에 접근한다.

 

 

당연히 비영속 상태다.

 

EntityManager.persist(entity) -> 영속 상태다.

 

 

준영속과 삭제 상태

 

 

 


 

영속성 컨텍스트의 이점

 

애플리케이션과 DB 사이에 무언가 낀 느낌인데.. 굳이? 라는 생각이 들지만 이러한 이점이 있다.

아래에서 하나씩 설명하도록 하겠다.

 

 

 


 

 

1차 캐시

 

다른 트랜잭션이라서 1차 캐시에는 없고 DB에만 member2가 존재한다는 가정이다. (member1은 1차 캐시에 존재함)

위와 같이 member1은 1차 캐시에서 꺼낼 수 있게 되고 (쿼리를 날리지 않게 됨),

member2는 1차 캐시에 없기 때문에 쿼리를 날려서 DB에서 값을 찾게 된다.

그 후, 1차 캐시에 DB에서 조회한 값을 저장한다.

 

 


 

 

 

영속 엔티티의 동일성 보장

 

 

 


 

 

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

 

INSERT 쿼리를 쓰기지연 SQL 저장소에 저장해뒀다가,

transaction.commit() 을 하는 순간 데이터베이스에 INSERT SQL을 보내게 된다.

 

 

 

 


 

 

 

변경 감지

 

위와 같이 em.update(member) 혹은 em.persist(member) 이런 코드를 실행시키지 않는다.

 

 

더티 체킹을 한다.

영속 컨텍스트에 해당 값이 들어오면, 엔티티와 스냅샷을 비교하여 다르다면 자동으로 UPDATE SQL을 생성한다.

 

 

 

 


 

 

 

플러시란?

영속성 컨텍스트의 변경내용을 데이터베이스에 반영하는 것

트랜잭션이 커밋되면 플러시가 자동으로 발생된다고 보면 된다.

 

 

플러시가 발생하게 되면,

1. 변경 감지

2. 수정된 엔티티 쓰기 지연 SQL 저장소에 등록

3. 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송 (등록, 수정, 삭제 쿼리)

위 3가지를 순서대로 실행하게 된다.

 

 

영속성 컨텍스트를 플러시하는 방법 (나중에 테스트를 위해 알아만 두자)

- em.flush() : 직접 호출

- 트랜잭션 커밋 : 플러시 자동 호출

- JPQL 쿼리 실행 : 플러시 자동 호출

 

 

위 코드를 실행하게 된다면, =========이 나오기 전에 sql이 실행된다. (직접 호출)

1차 캐시는 그대로 다 유지됨!

 

 

 

플러시 모드 옵션 2가지 : 웬만하면 AUTO로..

 

 

 

플러시는,

- 영속성 컨텍스트를 비우지 않음

- 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화

- 트랜잭션이라는 작업 단위가 중요 -> 커밋 직전에만 동기화하면 됨

 

 

 

 


 

 

 

준영속 상태란?

- 영속 -> 준영속

- 영속 상태의 엔티티가 영속성 컨텍스트에서 분리(detached)

- 영속성 컨텍스트가 제공하는 기능을 사용하지 못함

 

 

준영속 상태로 만드는 방법

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

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

- em.close() : 영속성 컨텍스트를 종료

 

 

위처럼 준영속 상태로 만든 후 em.find()를 한다면 select 쿼리가 다시 나감