LostCatBox

(JPA) JPA 기본편 CH02 (JPA 영속성 컨텍스트)

Word count: 564Reading time: 3 min
2023/04/06 34 Share

JPA에서 가장 중요한 것

  • 객체와 관계형 데이터베이스 매핑하기

  • 영속성 컨텍스트

개념

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

스크린샷 2023-04-06 오후 9.02.05

영속성 컨텍스트

  • 엔티티를 영구 저장하는 환경

  • EntityManager.persist(entity)

    persist는 DB에 저장하는것이 아니라 영속성 컨텍스트에 저장한다는 의미이다

  • 영속성 컨텍스트는 논리적인 개념

  • 엔티티 매니저를 통해서 영속성 컨텍스트에 접근함

엔티티의 생명주기

스크린샷 2023-04-06 오후 9.05.44

  • 비영속 (new/transient)
    영속성 컨텍스트와 전혀 관계가 없는 새로운 상태

  • 영속 (managed)
    영속성 컨텍스트에 관리되는 상태

  • 준영속 (detached)
    영속성 컨텍스트에 저장되었다가 분리된 상태

  • 삭제 (removed)
    삭제된 상태

비영속

  • 현재 JPA랑 관계없음

스크린샷 2023-04-06 오후 9.06.33

영속

  • 객체를 저장한 상태
  • 영속성 컨텍스트에 저장하지만 DB쿼리는 없음
  • Transaction commit 해야만 DB에 쿼리 날림
  • persist(),find() 를 할때도 영속 컨텍스트에 없엇다면, 생김

스크린샷 2023-04-06 오후 9.07.30

준영속

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

삭제

  • 객체를 삭제한 상태(삭제)
  • DB에서 해당 객체의 데이터 삭제 요청
  • em.remove(member)

영속성 컨텍스트의 이점

  • 1차 캐시
  • 동일성(identity) 보장
  • 트랜잭션을 지원하는 쓰기 지연
 (transactional write-behind)
  • 변경 감지(Dirty Checking)
  • 지연 로딩(Lazy Loading)

1차 캐시

  • DB 트랜잭션 단위로 영속 컨텍스트가 존재함(트랜잭션 끝나면 삭제됨)
  • 따라서 큰 효과는없음

스크린샷 2023-04-06 오후 9.13.49

동일성

  • 한 트랜잭션에서 같은 객체 find시 객체 참조값 같음. Equal

스크린샷 2023-04-06 오후 9.20.52

쓰기 지연

  • commit 이전까지 계속 영속 컨텍스트에만 쌓아둠
  • SQL문은 쓰기 지연 SQL 저장소에 쌓아둠 (trancsaction.commit시 DB에 쿼리 날림)
  • Hibernate의 batch_size 기능을 활용하여, SQL문을 한번에 보낼수있다.
1
2
3
4
5
6
7
8
9
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋

스크린샷 2023-04-06 오후 9.23.55

변경 감지 (더티 체킹)

  • 한 트랜잭션 안에서 변경사항 발생시 자동으로 DB에 마지막 쿼리로 update함
  • Transaction.commit() 시에 영속 컨텍스트의 스냅샷(읽은 최소 객체 상태 기억)과 비교하여 다른점을 update함
1
2
3
4
5
6
7
8
9
10
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(); // [트랜잭션] 커밋

스크린샷 2023-04-06 오후 9.31.13

제거(엔티티 삭제)

  • commit 시점에 delete쿼리 나감
1
2
3
//삭제 대상 엔티티 조회
Member memberA = em.find(Member.class, "memberA");
em.remove(memberA); //엔티티 삭제

플러시(flush)

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

(1차 캐시는 지워지지않는다. 트랜잭션이 끝나지 않았기 때문이다.)

동작

  • 변경 감지
  • 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
  • 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송 
 (등록, 수정, 삭제 쿼리)
  • 앞에 1,2번 진행후 DB에 쿼리 박히는 3번 진행함

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

  • em.flush() - 직접 호출
  • 트랜잭션 커밋 - 플러시 자동 호출
  • JPQL 쿼리 실행 - 플러시 자동 호출
    (em.createQuery(“[JPQL문]”)=>발생시 이때 DB에 이전 쿼리 반영하고난후 JPQL 동작 호출됨)

플러쉬 요약

  • 영속성 컨텍스트를 비우지 않음
  • 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화
  • 트랜잭션이라는 작업 단위가 중요 -> 커밋 직전에만 동기화 하면 됨

준영속 상태

  • 영속 -> 준영속
  • 영속 상태의 엔티티가 영속성 컨텍스트에서 분리(deteched)
  • 영속성 컨텍스트가 제공하는 기능을 사용 못함(더티 체킹 등등)

준영속 상태 만드는 법

  • em.detach(entity)
    특정 엔티티만 준영속 상태로 전환
  • em.clear()
    영속성 컨텍스트를 완전히 초기화
  • em.close()
    영속성 컨텍스트를 종료

JPA의 commit과 flush는 다르다.

출처

  • 트랜잭션을 begin() 으로 시작한 뒤 commit() 하여 트랜잭션을 종료해야한다.
  • commit()을 수행하게 되면 내부적으로 EntityManagerflush() 메서드를 호출한 후 트랜잭션을 닫습니다
  • flush는 쿼리를 전송하는 역할이고, commit은 내부적으로 flush를 수행한뒤 트랜잭션을 끝내는 역할입니다
  • 따라서, flush 로 전송된 쿼리는 rollback할 수 있다.(트랙잭션 중이므로), 하지만 commit은 트랜잭션을 끝내므로 rollback 할수없다.
CATALOG
  1. 1. JPA에서 가장 중요한 것
  2. 2. 개념
  3. 3. 플러시(flush)
  4. 4. 준영속 상태
  5. 5. JPA의 commit과 flush는 다르다.