본문 바로가기
Spring/JPA

[JPA] 영속성 컨텍스트 이점

by 잭피 2020. 12. 20.

안녕하세요~ 잭코딩입니다!

이번에는 JPA 영속성 컨텍스트의 이점에 대해 글을 써보려고 합니다!

지난 시간에는 영속성 컨텍스트가 무엇인지 살펴보았습니다

jackjeong.tistory.com/115

 

[JPA] 영속성 컨텍스트?

안녕하세요~ 잭코딩입니다! 이번에는 JPA 영속성 컨텍스트에 대해 글을 써보려고 합니다! 우캠 3주차에서 JPA 관련 미션을 수행하기 전에 학습한 내용을 정리해보려고 합니다 먼저 영속성 컨텍스

jackjeong.tistory.com

이번 시간에는 이어서 영속성 컨텍스트의 이점을 설명드리겠습니다


영속성 컨텍스트의 이점 

1. 1차 캐시

2. 동일성(identity) 보장

3. 트랜잭션을 지원하는 쓰기 지연(Transactional Write-behind)

4. 변경 감지(Dirty Checking)

 

하나씩 살펴볼까요?

 

1차 캐시

앞에서 배운 내용에서 em.persist()를 통해 영속 상태로 만든다고 하였습니다

이 영속 상태는 바로 DB에 저장하는 상태가 아닌, 영속성 컨텍스트에 의해 관리되는 상태를 의미합니다

 

영속성 컨텍스트에서 관리되는 엔티티는 1차 캐시에서 조회가 가능합니다 (단, @Id 조회일 경우만 가능합니다)

Station station = new Station();
station.setId("사당역");
station.setLine("4호선");

// 1차 캐시에 저장
em.persist(station);

// 1차 캐시에서 조회
Station station = em.find(Station.class, "사당역");

1차 캐시에 존재하는 경우 1차 캐시 조회 

DB에는 저장되어 있지만, 1차캐시에 데이터가 없다면 어떻게 될까요?

DB에서 조회를 해서 가져온 후, 1차 캐시에 저장하고 그 엔티티를 반환합니다

1차 캐시에 존재하지 않는 경우 DB조회

 

동일성(identity) 보장

영속성 컨텍스트(1차 캐시)에서 관리되는 엔티티를 가져왔을 경우 동일성을 보장합니다

    @Test
    void identity() {
        final Station station1 = stationRepository.save(new Station("잠실역"));
        final Station station2 = stationRepository.findById(station1.getId()).get();
        System.out.println("station1 : " + station1);
        System.out.println("station2 : " + station2);
        assertTrue(station1 == station2);
    }

동일한 참조값

station1, station2가 동일한 참조값을 가지고 있는 것을 확인할 수 있습니다

1차 캐시로 반복 가능한 읽기 등급의 트랜잭션 격리 수준을 DB가 아닌 애플리케이션 차원에서 제공합니다

 

트랜잭션을 지원하는 쓰기 지연(Transactional Wrtie-behind)

트랜잭션 커밋 전까지 SQL을 쓰기 지연 SQL 저장소에 보관합니다

그리고 커밋하는 순간 영속성 컨텍스트내 쓰기 지연 SQL 저장소에 보관된 SQL를 보냅니다

 

코드와 그림을 통해 볼까요?

transaction.begin();

em.persist(station1);
em.persist(station2);
// 커밋 전까지 INSERT SQL을 DB에 보내지 않습니다
// commit() 순간 DB에 INSERT SQL을 보냅니다
transaction.commit();

먼저 em.persist(station1)을 호출하는 경우, 쓰기 지연 SQL 저장소에 INSERT QUERY가 저장되고, 1차 캐시에 엔티티가 저장됩니다

 

em.persist(station1) 호출

 

그리고 em.persist(station2)를 호출하면 위와 같은 작업이 반복됩니다

 

em.persist(station2) 호출

마지막으로 commit()이 호출되면, 쌓아둔 SQL을 DB에 보내서 결과를 반영합니다

 

transaction.commit() 호출

변경 감지(Dirty Checking)

영속성 컨텍스트에서 관리하는 엔티티에 변경이 일어났을 경우 이를 감지합니다

Station station = em.find(Station.class, "사당역");

// 4호선 -> 2호선으로 변경
station.setLine("2호선")

transaction.commit();

em.update(station) 이런 코드가 따로 필요없습니다

엔티티 변경이 일어난 후, flush()가 발생하면 

1. 엔티티와 스냅샷을 비교합니다

2. UPDATE SQL을 생성하여 쓰기 지연 저장소에 저장합니다

3. 쌓여있는 쓰기 지연 SQL 저장소의 SQL을 DB에 반영합니다 

 

변경 감지(Dirty Checking)

 

플러시(flush)

flush()가 발생해야 영속성 컨텍스트의 변경내용을 DB에 반영합니다

플러시는 아래 3가지 상황에서 발생합니다

1. 변경 감지

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

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

 

실제 호출하는 방법은 아래와 같습니다

1. em.flush() : 직접 호출

2. 트랜잭션 commit() :  플러시가 자동으로 호출

3. JPQL 쿼리를 실행 : 플러시가 자동으로 호출

 

플러시는 영속성 컨텍스트를 비우지 않습니다

단순히 변경내용을 DB에 동기화해줍니다 

'Spring > JPA' 카테고리의 다른 글

[JPA] 영속성 컨텍스트?  (0) 2020.12.20

댓글