Everyday Dev System

영속성 컨텍스트의 기능 - 3가지 본문

내배캠 주요 학습/Spring 입문

영속성 컨텍스트의 기능 - 3가지

chaeyoung- 2023. 6. 14. 10:30

1. 1차 캐시

2023.06.14 - [내일배움캠프 공부/Spring 입문] - 영속성 컨텍스트 활용 - persist() , find() , remove()

 

영속성 컨텍스트 활용 - persist() , find() , remove()

1. 영속성 컨텍스트란? Entity 객체를 효율적으로 쉽게 관리하기 위해 만들어진 공간이다. EntityManager를 통해서 영속성 컨텍스트에 접근을 한다. em.persist(memo); -> 컨텍스트에 저장하고 싶은 Entity Clas

cdev.tistory.com

 

 

2. 쓰기 지연 저장소 (ActionQueue)

@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();
}

- commit을 아직 하지 않았기 때문에 컨텍스트 내에 ActionQueue에 담겨져있음.

 

 

** DB에 데이터를 반영하는 Query을 실행하기 위해서는 꼭 트랜잭션 환경이 필요하다.

 -> select는 상관이 없다.

EntityTransaction et = em.getTransaction();

et.begin();

et.commit();
et.rollback();

 

2-1) Flush()

- 쓰기 지연 저장소에 있던 Query문을 실행한다. 

flush는 쿼리를 전송하는 역할이고, commit은 내부적으로 flush를 수행한 뒤 트랜잭션을 끝내는 역할입니다.

즉 flush로 전송된 쿼리는 rollback할 수 있지만 commit은 트랜잭션을 끝내므로 rollback 할 수 없습니다

@Test
@DisplayName("flush() 메서드 확인")
void test7() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {
        Memo memo = new Memo();
        memo.setId(4L);
        memo.setUsername("Flush");
        memo.setContents("Flush() 메서드 호출");
        em.persist(memo);

        System.out.println("flush() 전");
        em.flush(); // flush() 직접 호출
        System.out.println("flush() 후\n");
        

        System.out.println("트랜잭션 commit 전");
        et.commit();
        System.out.println("트랜잭션 commit 후");

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

 

 

4. 변경 감지 - Dirty Checking

1) 변경하고 싶은 Entity를 찾아와서 1차 캐시에 저장한다. - em.find()

2) 해당 Entity 객체의 내용을 변경 - memo.setUsername("Update");

3) commit를 하면 자동으로 update가 된다.

@Test
@DisplayName("변경 감지 확인")
void test8() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {
        System.out.println("변경할 데이터를 조회합니다.");
        Memo memo = em.find(Memo.class, 4);
        System.out.println("memo.getId() = " + memo.getId());
        System.out.println("memo.getUsername() = " + memo.getUsername());
        System.out.println("memo.getContents() = " + memo.getContents());

        System.out.println("\n수정을 진행합니다.");
        memo.setUsername("Update");
        memo.setContents("변경 감지 확인");

        System.out.println("트랜잭션 commit 전");
        et.commit();
        System.out.println("트랜잭션 commit 후");

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

 

loadedState에는 Entity 최초 상태를 저장한다.

 

트랜잭션 commit되고, flush()가 호출되면

Entity의 현재 상태(entityInstance)와 loadedState를 비교한다.

 

값이 다르면 변경이 있는 것이므로, update SQL문을 생성하여 쓰기 지연 저장소에 저장한다. 

 

 

 

 

 

 

 

이와 같이 DB에 update가 잘 반영 됨을 알 수 있다.