[JPA] 영속성 관리

Jaeyoo (유재형)·2022년 3월 2일
1
post-thumbnail
post-custom-banner

게시물은 인프런 김영한님의 JPA 강의를 듣고 정리해보았습니다.


영속성 컨텍스트


영속성 컨텍스트란?

  • 엔티티를 영구 저장하는 환경
  • 엔티티 매니저를 통해 영속성 컨텍스트에 접근
  • em.persisit(entity) : entity를 영속성 컨텍스트에 저장

영속성 컨텍스트의 이점

영속성 컨텍스트를 사용함으로써 얻는 이점 5가지가 있다.

  1. 1차 캐시
  2. 동일성 보장
  3. 트랜잭션을 지원하는 쓰기 지연
  4. 변경감지
  5. 지연 로딩

1. 1차 캐시

//엔티티를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
//엔티티를 영속
em.persist(member)
//1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");
//1차 캐시에 없는것을 조회
Member findMember2 = em.find(Member.class, "member2");
  • @Id와 member객체 자체가 값이 된다.
  • 조회시 DB가 아닌 1차 캐시에서 찾는다.
  • 만약 1차 캐시에 없는것을 조회하면 DB에 조회후 그 값을 1차 캐시에 저장후 반환한다.

2. 영속 엔티티의 동일성 보장

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

System.out.println(a == b); //동일성 비교 true
  • JPA가 영속 엔티티의 동일성을 보장해준다. (1차 캐시가 있기때문에 가능)

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

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

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

persist()

  • persist(memberA)
  1. memberA가 1차 캐시에 저장됨
  2. 동시에 INSERT SQL을 생성해 쓰기 지연 SQL 저장소에 저장
  • persist(memberB)
  1. memberB가 1차 캐시에 저장됨
  2. 동시에 INSERT SQL을 생성해 쓰기 지연 SQL 저장소에 저장

commit()

  • transaction.commit()
  1. 내부적으로 flush 발생
    • dirth checking 후 쓰기지연 SQL 저장소의 쿼리를 DB에 전송 (dirty checking은 바로 다음에 설명)
  2. DB에 commmit

    쓰기지연을 하는 이유

    • 여러 쿼리를 하나의 트랜잭션으로 묶을 수 있다.
    • DB에 한번에 보낼수있어 네트워크 트래픽을 감소해 성능을 향상 시킬 수 있다.
    • 버퍼링과 관련된 기능으로 jdbc의 batch 부분을 참고하면 될 것.

4. 엔티티 수정 (Dirty Checking)

// 영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);
//em.update(member) 이런 코드가 있어야 하지 않을까?
transaction.commit(); // 트랜잭션 커밋
  • JPA는 commit()시에 내부적으로 flush가 호출된다.
  • flush 호출
    • 엔티티와 스냅샷을 비교 (엔티티는 값을 읽어온 최초 시점을 기록해놓는다.)
    • 스냅샷과 다르다면 UPDATE 쿼리를 생성해 쓰기지연 저장소에 저장한다.
    • 쿼리를 DB에 반영
  • commit 실행

5. 엔티티 삭제

//삭제 대상 엔티티 조회
Member memberA = em.find(Member.class, “memberA");

em.remove(memberA); //엔티티 삭제
  • 수정 부분과 매커니즘 동일
  • DELETE 쿼리 생성

플러시 (flush)


플러시란?

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

플러시 과정

  1. 변경 감지
  2. 엔티티를 수정하기위해 해당 쿼리를 쓰기지연 SQL 저장소에 등록
  3. 쓰기지연 저장소의 쿼리를 DB에 전송

플러시하는 방법

  1. 직접 호출 : em.flush()
  2. 커밋 : em.commit()
  3. JPQL 쿼리 실행
    • JPQL의 명령어가 올바르게 작동하기위해 JPQL을 보내기전에 자동으로 flush를 한다.

flush를 해도 1차 캐시는 비워지지않는다. 1차캐시와 flush는 관계 없음.

profile
기록과 반복
post-custom-banner

0개의 댓글