영속성 관리 - 내부 동작 방식(플러시, 준영속 상태)

ANN·2024년 12월 9일
0

JPA(TIL)

목록 보기
3/4
post-thumbnail

해당 내용은 인프런 김영한 강사님의 '자바 ORM 표준 JPA 프로그래밍 - 기본편'의 강의를 기반으로 작성했습니다.

https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

📢플러시(Flush)

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

보통 데이터베이스 트랜잭션이 딱 commit될 때 flush발생
= 영속성 컨텍스트에 쌓아둔 SQL이 데이터베이스에 날아가는 것

쉽게 이야기해서, 영속성 컨텍스트의 현재 변경 사양과 데이터베이스를 딱 맞추는 작업

❓플러시 발생

플러시는 트랜잭션이 커밋되면 자동으로 발생

  • 변경 감지
  • 수정된 엔티티가 "쓰기 지연 SQL 저장소"에 등록
  • 쓰기 지연 SQL 저장소에 있는 쿼리(등록, 수정, 삭제 등 쿼리)를 데이터베이스에 전송

단, Flush가 발생했다고 트랜잭션이 commit되는 건 아님(다른 단계임)

❓영속성 컨텍스트를 플러시하는 방법

1. 직접 호출

직접 쓸 일은 거의 없지만, 알아둬야 함

em.flush();

원래는 커밋되기 전에 쿼리를 볼 수 없는데,

  • 미리 데이터베이스에 반영하고 싶거나,
  • 쿼리를 미리 보고 싶을 때 사용

flush하는 순간, 쿼리가 출력이 되면서 commit전에 DB에 반영
그리고 이후 commit

혹시 flush하면 1차 캐시는 어떻게 되나요?
유지됩니다.
flush는 영속성 컨텍스트의 쓰기 지연 SQL 저장소에 있는 쿼리를 날릴 뿐

잠깐, 이 코드 실행은 어떻게 될까?

em.persist(memberA);
em.persist(memberB);
em.persist(memberC);

//중간에 JPQL 실행
query = em.createQuery("select m from Member m", Member.class);
List<Member> members= query.getResultList();
  • JPQL 쿼리를 실행하면 member A, B, C가 조회될까?
  • 배웠던 내용만 생각하면, persist는 되었지만 commit은 되지 않았으므로 조회가 안 되지 않을까?

결론적으로 말하면, 조회가 된다.

2. JPQL 쿼리 실행

위와 같은 예제 코드처럼 JPQL 쿼리를 실행하면, 그 순간 flush를 날림
그래야 이후 문제가 없음

3. 트랜잭션 커밋

여태 배운 것처럼 commit되는 순간, flush가 자동으로 실행

❓플러시 모드 옵션

em.setFlushMode(옵션~)

FlushModeType.AUTO

커밋이나 쿼리를 실행할 때 플러시(기본값)

FlushModeType.COMMIT

커밋할 때만 플러시
= 쿼리를 실행할 땐 플러시하지 않음
위 옵션을 설정하고,

em.persist(memberA);
em.persist(memberB);
em.persist(memberC);

//중간에 JPQL 실행
query = em.createQuery("select m from Member m", Member.class);
List<Member> members= query.getResultList();

아래 코드를 실행하면 flush하지 않기 때문에 memberA, B, C가 조회되지 않을 것
-> 단순 해당 테이블을 조회하고 싶거나, 다른 테이블을 조회하고 싶거나 할 때 사용

다만 손대지 말고 기본값 쓰십쇼

❗️플러시는,

  • 영속성 컨텍스트를 비우지 않음
  • 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화
  • 이 매커니즘 동작 방식은 트랜잭션이 있기 때문에 가능
    • 트랜잭션이라는 작업 단위가 중요
    • commit 직전에 동기화

📢 준영속 상태


지금 배워도 어려운 개념이라 이런 게 있다고 알고 넘어가자~

  • em.persist하면 영속상태가 됨
  • 혹은, em.find를 했는데 1차 캐시에 없고 DB에서 가져와 1차 캐시에 올림
    = 영속 상태가 됨
    = JPA가 관리하는 상태가 됨

그럼 준영속은 뭐지?
영속 상태의 엔티티가 영속성 컨텍스트에서 분리하는 것
즉, 다 빼버리는 것
-> 그러면 영속성 컨텍스트가 제공하는 더티 체킹 등을 사용 못함

❓준영속 상태로 만드는 방법

1. em.detach(entity)

특정 엔티티만 준영속 상태로 전환

  • 조회해온 엔티티(select 쿼리 출력됨)는 JPA 관리 하에 있는 데이터일 텐데,
  • detach는 이 엔티티와 JPA를 분리
  • 엔티티를 변경했지만 그 후 detach를 했으므로 commit해도 insert 쿼리가 출력되지 않음

직접 쓸 일이 없는데, 나중에 이해가 될 것임

2. em.clear()

해당 영속성 컨텍스트를 초기화

똑같은 것을 조회해도, 영속성 컨텍스트가 초기화 되었으므로 select 쿼리가 두 번 나감

3. em.close()

영속성 컨텍스트를 종료

0개의 댓글