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

1. 영속성 컨텍스트

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

1.1. JPA 에서 가장 중요한 2가지

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

sec3  사진1

1.1.1. 엔티티의 생명주기

sec3  사진2

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

1.1.2. 영속성 컨텍스트의 이점

1.1.2.1. 1차 캐시

sec3  사진3

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

1.1.2.2. 동일성(identity) 보장

<code />
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에서 제공한다.

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

<code />
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로 설정 가능)

1.1.2.4. 변경 감지 (Dirty Checking)

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

sec3  사진4

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

1.1.2.5. 지연 로딩 (Lazy Loading)

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

1.1.3. 플러시

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

1.1.3.1. em.flush()

<code />
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(); }
  • 직접 쓸일은 없지만, 테스트할 때 사용한다.
<code />
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)과 같이 플러시 모드를 변경할 수도 있다.

1.1.4. 준영속 상태

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

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

반응형
profile

제육's 휘발성 코딩

@sasca37

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