-
영속성 컨텍스트의 기능spring/스프링 입문 주차 2024. 1. 25. 09:39
영속성 컨텍스트는 Entity 객체를 효율적으로 쉽게 관리하기 위해 만들어진 공간이다.
- 영속성 컨텍스트가 어떻게 Entity 객체를 효율적으로 관리하고 있는지 살펴보자
영속성 컨텍스트는 내부적으로 캐시 저장소를 가지고 있다.
- 우리가 저장하는 Entity 객체들이 1차 캐시 즉, 캐시 저장소에 저장된다고 생각하면 된다.
- 캐시 저장소는 Map 자료구조 형태로 되어있다.
- key에는 @Id로 매핑한 기본 키 즉, 식별자 값을 저장한다.
- value에는 해당 Entity 클래스의 객체를 저장한다.
- 영속성 컨텍스트는 캐시 저장소 Key에 저장한 식별자 값을 사용하여 Entity 객체를 구분하고 관리한다.
영속성 컨텍스트가 이 캐시 저장소를 어떻게 활용하고 있는지 살펴보자.
- em.persist() 메서드가 호출되면 Entity 객체를 캐시 저장소에 저장한다.
- em > persistenceContext > entitiesBykey를 확인해 보면 key-value 형태로 정보가 저장되어있음을
확인할 수 있다.
Entity 조회
1. 캐시 저장소에 조회하는 Id가 존재하지 않는 경우
a 캐시 저장소 조회
b DB SELECT 조회 후 캐시 저장소에 저장
- em.find(Memo.class, 1) 호출 시 캐시 저장소를 확인 한 후 해당 값이 없다면,
DB에 SELECT 조회 후 해당 값을 캐시 저장소에 저장하고 반환한다.
2. 캐시 저장소에 조회하는 Id가 존재하는 경우
- em.find(Memo.class, 1) 호출 시 캐시 저장소에 식별자 값이 1이면서 Memo Entity 타입인 값이 있는지 조회
- 값이 있다면 Entity 객체를 반환한다.
1차 캐시 사용의 장점
1. DB 조회 횟수를 줄임
2. '1차 캐시'를 사용해 DB row 1개 당 객체 1개가 사용되는 것을 보장(객체 동일성 보장)
Entity 삭제
1. 삭제할 Entity를 조회한 후 캐시 저장소에 없다면 DB에 조회해서 저장한다.
2. em.remove(entity);
- em.remove(memo) 호출 시 삭제할 때 Entity를 DELETE 상태로 만든 후 트랜잭션 commit 후
Delete SQL이 DB에 요청된다.
쓰기 지연 저장소(ActionQueue)
JPA의 트랜잭션 학습하면서 JPA가 트랜잭션 처럼 SQL을 모아서 한번에 DB에 반영한다는 것을 배웠다.
- JPA는 이를 구현하기 위해 쓰기 지연 저장소를 만들어 SQL을 모아두고 있다가 트랜잭션
commit 후 한번에 DB에 반영한다.
- Debugging을 통해 실제로 쓰기 지연 저장소에 SQL을 모아서 한번에 반영하는지 확인해보자.
- 실제로 기록을 확인해보면 트랜잭션 commit 호출 전까지는 SQL 요청이 없다가 트랜잭션 commit 후
한번에 Insert SQL 2개가 순서대로 요청된 것을 확인할 수 있다.
flush()
- 트랜잭션 commit 후 쓰기 지연 저장소의 SQL들이 한번에 요청됨을 확인했다.
- 사실 트랜잭션 commit 후 추가적인 동작이 있는데 바로 em.flush(); 메서드의 호출이다.
- flush 메서드는 영속성 컨텍스트의 변경 내용들을 DB에 반영하는 역할을 수행한다.
- 즉, 쓰기 지연 저장소의 SQL들을 DB에 요청하는 역할을 수행한다.
- em.flush(); 메서드가 호출되자 바로 DB에 쓰기 지연 저장소의 SQL이 요청되었다.
- 이미 쓰기 지연 저장소의 SQL이 요청 되었기 때문에 더 이상 요철청할 SQL이 없어 트랜잭션이
commit 된 후에 SQL 기록이 보이지 않는다.
- 추가) 트랜잭션을 설정하지 않고 flush 메서드를 호출하면 no transaction is in progress 메시지와 함께
TransactionRequiredException 오류가 발생합니다.
- Insert, Update, Delete 즉, 데이터 변경 SQL을 DB에 요청 및 반영하기 위해서는 트랜잭션이 필요하다.
(Select 는 상관 없음)
commit 메서드엔 flush 기능이 포함되어 있다는 걸 알 수 있다.
변경 감지(Dirty Checking)
- 영속성 컨텍스트에 저장된 Entity가 변경될 때 마다 Update SQL이 쓰기 지연 저장소에 저장된다면?
- 하나의 Update SQL로 처리할 수 있는 상황을 여러번 Update SQL을 요청하게 되기 때문에 비효율적이다.
- 그렇다면 JPA는 어떻게 Update를 처리할까?
- em.update(entity) 같은 메서드를 지원할 것 같지만 찾아볼 수 없다.
- JPA에서는 Update를 어떻게 처리하는지 살펴보자.
- JPA는 영속성 컨텍스트에 Entity를 저장할 때 최초 상태(LoadedState)를 저장한다.
- 트랜잭션이 commit되고 em.flush(); 가 호출되면 Entity의 현재 상태와 저장한 최초 상태를 비교한다.
- 변경 내용이 있다면 Update SQL을 생성하여 쓰기 지연 저장소에 저장하고 모든 쓰기 지연 저장소의
SQL을 DB에 요청한다.
- 마지막으로 DB의 트랜잭션이 commit 되면서 반영된다.
- 따라서 변경하고 싶은 데이터가 있다면 먼저 데이터를 조회하고 해당 Entity 객체의 데이터를 변경하면
자동으로 Update SQL이 생성되고 DB에 반영된다.
- 이러한 과정을 변경 감지, Dirty Checking이라 부른다.
변경 감지 또한 마찬가지로 트랜잭션이 걸려 있어야 한다.'spring > 스프링 입문 주차' 카테고리의 다른 글
SpringBoot의 JPA (1) 2024.01.25 엔티티의 상태 (1) 2024.01.25 JPA란 무엇일까 (0) 2024.01.23 제어의 역전, ApplicationContext (2) 2024.01.22 IoC Container 와 Bean (0) 2024.01.22