[Spring JPA] 영속성 컨텍스트의 기능
2024. 3. 7. 18:43ㆍBE/Spring
본 포스팅은 영속성 컨텍스트의 4가지 기능을 다룹니다.
영속성 컨텍스트란?
- 영속성 컨텍스트는 Spring JPA의 Entity 객체를 관리하기 위해 만들어진 공간
- 영속성 컨텍스트에 저장하기 위해 Entity Manager 객체가 persist 메소드를 호출해야함.
- Entity Manager는 @PersistenceContext를 통해 의존성 주입을 받을 수 있음
- 영속성 컨텍스트에 저장한 후, commit메소드를 호출해야 db에 반영이됨.
트랜잭션이란?
- 트랜잭션은 DB 데이터들의 무결성과 정합성을 유지하기 위한 하나의 논리적 개념
- 여러 개의 쿼리들이 하나의 트랜잭션에 포함될 수 있고, 여러 개의 쿼리들을 모아 한 번에 db에 반영함.
- 모든 쿼리들이 성공적으로 수행되면 영구적으로 db에 변경을 반영하지만, 하나라도 실패하면 모든 변경 사항을 되돌림.
1차 캐시
- entity manager가 persist 메소드를 호출하면
- entity 객체가 1차 캐시에 저장됨.
- 비영속(New/Transient) 상태인 Entity 객체를 영속(Managed)상태로 만듬
- 쓰기지연 SQL 저장소에 INSERT 쿼리를 생성함
- 조회를 할 때, 1차 캐시에 있으면 1차 캐시에 있는 정보를 통해 조회를 진행하고, 1차 캐시에 없으면 db에 요청을 보내 조회함.
장점
- 1차 캐시를 사용하면 db에 요청 보내는 횟수가 줄어들어 속도가 향상될 수 있음.
쓰기 지연 SQL 저장소
- entity manager가 persist 메소드를 호출하면 SQL 쿼리들이 쓰기 지연 저장소에 저장됨.
- commit 메소드가 호출되면, flush가 되면서 쓰기 지연 저장소에 있는 모든 SQL 쿼리들이 db에 반영됨.
@Test
@DisplayName("쓰기 지연 저장소 확인")
void test6() {
EntityTransaction et = em.getTransaction();
et.begin();
try {
Memo memo = new Memo();
memo.setId(2L);
memo.setUsername("Robbert");
memo.setContents("쓰기 지연 저장소");
em.persist(memo);
Memo memo2 = new Memo();
memo2.setId(3L);
memo2.setUsername("Bob");
memo2.setContents("과연 저장을 잘 하고 있을까?");
em.persist(memo2);
System.out.println("트랜잭션 commit 전");
et.commit();
System.out.println("트랜잭션 commit 후");
} catch (Exception ex) {
ex.printStackTrace();
et.rollback();
} finally {
em.close();
}
emf.close();
}
변경 감지(Dirty Checking)
- entity manager의 commit 메소드가 호출되면, 내부적으로 flush 메소드가 먼저 호출됨
- flush 메소드가 호출되면, 1차 캐시에 저장된 엔티티와 엔티티의 최소 상태인 스냅샷(LoadedState)을 비교함
- 만약 변경 사항이 있다면, 업데이트 sql 쿼리를 쓰기 지연 sql 저장소에 저장함
- 쓰기 지연 sql 저장소에 있는 sql 쿼리들이 flush 되면서 db에 반영됨
동일성 보장
- 영속성 컨텍스트는 1차캐시를 이용해 동일한 @Id 를 가지는 Entity 에 대한 동일성 보장을 해준다.
- Entity 를 조회한다는 것은 아래와 같은 흐름을 거치게된다.
- (@Id 를 이용한 조회라면) 1차캐시에 @Id 에 해당하는 Entity 가 있는지 먼저 조회한다.
- 만약 1차 캐시에 @Id에 해당하는 Entity가 있다면, 1차 캐시에 있는 Entity를 반환함
- 없으면 아래의 절차 진행
- 데이터베이스에 SELECT 쿼리를 실행해 Entity 정보를 조회한다.
- 조회한 Entity 를 영속(Managed) 상태로 만든다. → 이때 1차캐시에도 저장된다!!
- 1차캐시에 저장된 Entity 를 반환한다.
- (@Id 를 이용한 조회라면) 1차캐시에 @Id 에 해당하는 Entity 가 있는지 먼저 조회한다.
- 즉, 조회 결과로 나온 Entity 는 항상 영속 상태이며 1차캐시에 저장되어 관리되는 Entity 다.
- 그리고 1차캐시에는 @Id 하나당 하나의 Entity 를 저장해두고 있기 때문에 여러번 조회하더라도 @Id 가 같다면 해당 Entity 들은 모두 동일한 주소를 가지는 인스턴스가 된다!! (단, 모든 Entity 가 영속 상태라는 전제가 필요하다!!)
헷갈리는 것
- commit 메소드, flush 메소드, flush는 어떻게 다른 것일까 ?
- commit 메소드가 호출되면, flush 메소드가 호출됨.
- flush 메소드가 호출되면 변경 사항에 대해 업데이트 쿼리를 쓰기 지연 저장소에 저장한 후 db에 반영이 되는데, 이러한 과정 자체를 flush 작업이 수행된다고 지칭함.
- 즉, commit 메소드가 호출되면 flush 작업이 수행되는데, 이를 flush 라는 이름의 메소드를 호출하여 진행하는 것
추가 정리
- flush 메소드는 영속성 컨텍스트를 비우지는 않고, 영속성 컨텍스트의 변경 내용을 데이터베이스에 flush하게됨.
- 만약 flush 메소드를 호출한 후, commit 메소드를 호출하면 쿼리가 날라가지 않게됨
- 영속성 컨텍스트와 트랙잭션의 생명주기는 동일하다.
'BE > Spring' 카테고리의 다른 글
[Spring Security] URI에 따라 접근 권한 부여하기 최신 버전 (0) | 2024.03.05 |
---|---|
[Spring Security] 최신! 로그인 결과를 ResponseBody에 나타내는 법 (0) | 2024.03.05 |
[Spring] Failed to load remote configuration. (0) | 2024.03.01 |
[Spring] 의존성 주입(DI)과 제어의 역전(IoC) (0) | 2024.02.25 |
[Spring] 초간단! 인자의 종류 (0) | 2024.02.24 |