Spring JPA 영속성 컨텍스트

2021. 2. 28. 21:12Spring/JPA

영속성 컨텍스트

엔티티 매니저 팩토리와 엔티티 매니저

2021-02-20-4-59-27.png

  • 영속성 컨텍스트란??
    • JPA를 이해하는데 가장 중요한 언어
    • "엔티티를 영구 저장하는 환경" 이라는 뜻
    • EntityManager.persist(entity);
  • 엔티티 매니저? vs 영속성 컨텍스트?
    • 영속성 컨텍스트는 논리적인 개념
    • 눈에 보이지 않는다.
    • 엔티티 매니저를 통해서 영속성 컨텍스트에 접근

J2SE 환경

  • 엔티티 매니저와 영속성 컨텍스트가 1:1

PersistenceContext는 눈에 보이지 않는 공간이라고 생각하면 된다.

2021-02-20-4-59-57.png


엔티티 생명주기

비영속

2021-02-20-5-00-21.png

객체를 생성한 상태(비영속)
Member member = new Member();
member.setId(1L);
member.setUserName("User1")

영속

2021-02-20-5-00-47.png

//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId(1L);
member.setUserName("User1");

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

//객체를 저장한 상태(영속) 그리고 여기서 DB에 member가 저장되지 않는다.!!!
em.persist(member);

준영속, 삭제

//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);

//객체를 삭제한 상태(삭제)
em.remove(member);

엔티티 조회, 1차 캐시

2021-02-20-6-23-25.png

//엔티티를 생성한 상태(비영속)
Member member = new Member();
member.setId(1L);
member.setUserName("User1");

//객체를 저장한 상태(영속) 그리고 여기서 DB에 member가 저장되지 않는다.!!!
em.persist(member);

2021-02-20-6-23-48.png

Member member = new Member();
member.setId(1L);
member.setUserName("User1");

//1차 개시에 저장됨
em.persist(member);

//1차 캐시에서 조회
Member findMember = em.find(Member.class, 1L);

DB에서 조회

Member findMember2 = em.find(Member.class, 2L);

2021-02-20-6-24-15.png

  • 1차 캐시는 EntityManager에서 사용되는거기 때문에 사용자가 하나의 트랜잭션을 끝내면 1차 캐시에 저장된 값들도 날아가 버린다. 그래서 성능의 크게 이점은 없다.

영속 엔티티의 동일성 보장

Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");

System.out.println(a == b); // true
  • 이것이 가능한 이유는 1차 캐시가 있기 때문이다.

엔티티 등록(트랜잭션을 지원하는 쓰기 지연)

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); //[트랜잭션] 시작

em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.

//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); //[트랜잭션] 커밋

2021-02-20-6-26-00.png

2021-02-20-6-26-22.png

엔티티 수정(변경 감지)

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); //[트랜잭션] 시작

//영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");

//영속 엔티티 데이터 수정
memberA.setUserName("hi");
memberA.setAge(10);

//em.update(member); 이런 코드가 있어야 하지 않을까?

transaction.commit(); //[트랜재션] 커밋

2021-02-20-6-24-49.png


Flush

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

플러시 발생

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

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

  • em.flush - 직접 호출
  • 트랜잭션 커밋 - 플러시 자동 호출
  • JPQL 쿼리 실행 - 플러시 자동 호출

플러시를 하면 1차 캐시가 지워지지는 않는다. 그냥 영속성 컨텍스트가 DB에 반영되는 것일 뿐!!

JPQL 쿼리 실행시 플러시가 자동으로 호출되는 이유

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

//중간에 JPQL 실행
query = em.createQuery("select m from Member m", Member.class0;);
List<Member> members = query.getResultList();
  • 만약 플러시가 자동으로 호출 되지 않는다면 위에 코드에서 persist의 객체들이 쓰기 지연으로 인해 아직 DB에 반영이 되지 않은 상태!
    이 상태에서 Jpql을 실행하면 DB에 값들이 없어서 List에 아무 값들이 없다. 그래서 JPQL실행시 이러한 오류를 방지하고자 자동으로 호출된다.

정리!!!

  1. 영속성 컨텍스트를 비우지 않는다.
  2. 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화
  3. 트랜잭션이라는 작업 단위가 중요 -> 커밋 직전에만 동기화 하면된다.
  4. 영속성 컨텍스트의 이점
      1. 1차캐시
      2. 동일성 보장
      3. 트랜잭션을 지원하는 쓰기 지연
      4. 변경 감지(Dirty Checking)
      5. 지연 로딩(Lazy Loading)

참고

  • 위 내용은 인프런 김영한님의 JPA기본편에서 정리한 내용입니다.

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

Spring JPA [상속관계 맵핑]  (0) 2021.06.17
[Spring JPA] 다양한 연관관계 매핑  (0) 2021.04.19
Spring JPA 엔티티 맵핑  (0) 2021.02.27
JPA 개발 들어가기  (0) 2021.02.19
JPA는 왜 사용하는가?  (0) 2021.02.19