제육's 휘발성 코딩
반응형

영속성 컨텍스트

  • "엔티티를 영구 저장하는 환경"이라는 뜻 (DB의 저장이라기보다, 영속성 컨텍스트에 저장한다는 의미)
  • EntityManager.persist(entity); - 엔티티 매니저를 통해 영속성 컨텍스트에 접근

JPA 에서 가장 중요한 2가지

  • 객체와 관계형 데이터베이스 매핑하기 (Object Relational Mapping)
  • 영속성 컨텍스트

sec3  사진1

엔티티의 생명주기

sec3  사진2

  • 비영속 (new/transient) - 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
// 객체만 생성한 상태 (비영속)
Member member = new Member();
member.set~
  • 영속(managed) - 영속성 컨텍스트에 관리되는 상태 - DB에 저장되는게 아니다. 저장은 commit
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(member);
  • 준영속(detached) - 영속성 컨텍스트에 저장되었다가 분리된 상태
em.detach(member);
  • 삭제 (removed) - 삭제된 상태
em.remove(member);

영속성 컨텍스트의 이점

1차 캐시

sec3  사진3

  • 조회하려는 값이 1차 캐시에 없으면 DB에서 조회 후 1차 캐시에 등록 후 반환하고, 값이 있으면 DB에 접근 하지 않고 1차 캐시에서 바로 꺼내온다.
  • 하나의 트랜잭션 안에서만 영속성 컨텍스트가 생성되고 종료되기 때문에 정말 복잡한 애플리케이션이 아니라면 큰 차이가 없다. 여러 트랜잭션을 관리하는 것은 2차 캐시이다.

동일성(identity) 보장

Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); //동일성 비교 true
  • 1차 캐시로 REAPEATABEL READ 등급의 트랜잭션 격리 수준을 DB가 아닌 애플리케이션 차원에서 제공한다. 마치 자바의 컬렉션에서 값을 꺼낼 때 동일함을 보장해야한다는 것을 JPA에서 제공한다.

트랜잭션을 지원하는 쓰기 지연

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
transaction.commit(); // [트랜잭션] 커밋
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
  • JPA가 커밋하기 전까지 쌓아두었다가 커밋 시에 한꺼번에 적용 (hibernate.batch size로 설정 가능)

변경 감지 (Dirty Checking)

Member memberA = em.find(Member.class, "memberA");
memberA.setUsername("hi");
memberA.setAge(10);
transaction.commit();
  • update 관련 쿼리 없이 set으로 수정이 가능하다.

sec3  사진4

  • 트랜잭션을 커밋하는 순간 영속성 컨텍스트에서 flush() 가 호출
  • 스냅샷과 비교해서 변경사항이 있으면 SQL 생성하여 flush , commit
  • 예) 값을 바꾸면 set~ 만해주면 자동으로 변경해준다.

지연 로딩 (Lazy Loading)

  • 지연 로딩 : 객체가 실제 사용될 때 로딩
    • 처음에 member에 데이터만 갖고왔다가 team을 쓰려고할 때 team 데이터까지 가지고온다.

플러시

  • 영속성 컨텍스트의 변경내용을 데이터베이스에 반영하는 것을 의미한다. 즉, 영속성 컨텍스트를 비우는 것이 아니라 변경 내용을 디비에 동기화 하는 것이다.
  • 영속성 컨텍스트를 플러쉬하는 방법 : em.flush(), 트랜잭션 커밋, JPQL 쿼리 실행

em.flush()

try {

    Member member = new Member(200L, "member200");
    em.persist(member);

    em.flush(); // 강제 호출
    System.out.println("==========================="); // === 전에 쿼리문이 나간다.
    tx.commit();
} catch (Exception e){
    tx.rollback();
} finally {
    em.close();
}
  • 직접 쓸일은 없지만, 테스트할 때 사용한다.
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 실행 문 전까지는 영속성 컨텍스트에 담겨있다. JPQL문 부터는 해당 데이터를 조회해야하므로, 이때 flush()를 사용하여 DB에 모두 동기화 하고 JPQL을 동작할 수 있도록 한다.

플러시는 영속성 컨텍스트를 비우는 것이 아닌 변경 내용을 DB에 동기화 하는 것이다. 즉, 트랙잭션이 커밋하기 직전에만 동기화 한다고 생각하자. em.setFlushMode(FlushModeType.COMMIT)과 같이 플러시 모드를 변경할 수도 있다.

준영속 상태

  • 준영속 상태란 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 상태를 의미한다. (detached)
  • 영속성 컨텍스트가 제공하는 기능을 사용하지 못한다.
  • em.detach(entity) : 특정 엔티티만 준영속 상태로 전환
  • em.clear() : 영속성 컨텍스트를 완전히 초기화
  • em.close() : 영속성 컨텍스트를 종료

본 포스팅은 인프런 김영한님 강의(자바 ORM 표준 JPA 프로그래밍 - 기본편)를 토대로 정리한 내용입니다.

반응형
profile

제육's 휘발성 코딩

@sasca37

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요! 맞구독은 언제나 환영입니다^^