본문 바로가기
Spring/JPA

영속성 관리

by o3oppp 2023. 8. 22.

영속성 컨텍스트

  • 엔티티를 영구 저장하는 환경
  • EntityManger.persist(entity);
  • 논리적인 개념으로 눈에 보이지 않음
  • 엔티티 매니저를 통해서 영속성 컨텍스트에 접근
  • 내부에 1차 캐시, 쓰기 지연 SQL 존재

 

엔티티 생명주기

  1. 비영속
    • 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
  2. 영속
    • 영속성 컨텍스트에 관리되는 상태로 영속성 컨텍스트 안에 객체가 들어간다고 생각
    • em.persist 이후 바로 데이터베이스 쿼리가 나가는 것이 아닌, commit 순간에 영속성 컨텍스트 안의 객체가 데이터베이스로 날아감
  3. 준영속
    • 영속성 컨텍스트에서 분리된 상태(detached)
    • 영속성 컨텍스트가 제공하는 기능을 사용 못함(commit 등)
    • em.detach(entity) : 해당 entity를 준영속 상태로 만듬
    • em.clear() : 영속성 컨텍스트 자체를 초기화
    • em.close() : 영속성 컨텍스트 종료
  4. 삭제
    • 삭제된 상태
// 객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

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

// 객체를 저장한 상태(영속)
em.persist(member); 

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

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

 

영속성 컨텍스트의 장점

  1. 영속성 컨텍스트 내에 1차 캐시 존재 (동일한 트랜잭션 내에서만 동일한 1차 캐시에 저장)
// 1차 캐시에 저장
em.persist(member);

 // 1차 캐시에 있으면 db를 거치지 않고 바로 조회, SELECT 쿼리 로그 없음
em.find(Member.class, "member1");

// 1차 캐시에 없으면 db에서 조회, SELECT 쿼리 로그 있음
// 조회 후 다시 1차 캐시에 저장 후 반환
em.find(Member.class, "member2");

// 이후 member2 조회 시 1차 캐시에서 조회, SELECT 쿼리 로그 없음

   2. 동일성 보장

Member findMember1 = em.find(Member.class, 101L);
Member findMember2 = em.find(Member.class, 101L);
    
System.out.println("result = " + (findMember1 == findMember2)); // true

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

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

em.persist(memberA);
em.persist(memberB);
// 여기까지 INSERT SQL을 DB에 보내지 않음
// 로그에서 INSERT SQL 안나옴

// 커밋하는 순간 DB에 INSERT SQL을 보냄
tx.commit(); // 트랜잭션 커밋
  • persist 시 쓰기 지연 SQL 저장소에 저장
  • commit 순간에 지연 SQL 저장소에 쌓인것들 모두 저장
  • persistence.xml에서 배치 사이즈 조절을 통해 원하는 개수의 SQL 설정 가능 

commit 실행 시

   4. 변경 감지(Dirty checking)

Member findMember = em.find(Member.class, 150L);
findMember.setName("B"); // A -> B 로 변경됨, 이 순간 update 쿼리는 날아감

// em.persist(findMember); // 불필요
...
tx.commit();
  • update 시 em.persist 호출 불필요
  • 쉽게 생각해서 자바 컬렉션에서 인덱스를 통한 데이터에 접근하여, 데이터 수정 후 다시 저장하지 않는 것과 비슷

 

플러시

  • 흔히 '영속성 컨텍스트를 플러시 한다' 라고 표현
  • 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 것(동기화)
  • 플러시 발생은 commit 실행 시 자동으로 발생하나 직접 호출 또한 가능
    • 자동
      • 변경 감지 시 
      • 수정된 엔티티 쓰기 지연 SQL 저장소에 등록 시
      • 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스 전송 시
    • 직접 호출
      • em.flush()
      • commit 실행
      • JPQL 쿼리 실행 (em.createQuery("select m from Member m", Member.class);)
  • 영속성 컨텍스트를 비우지 않음
  • 1차 캐시와는 무관(1차 캐시의 내용이 지워지지 않음)
  • 트랜잭션 작업 단위가 중요 -> commit 직전에만 동기화 하면 됨

 

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

MappedSuperclass  (0) 2023.12.20
상속관계 매핑  (0) 2023.12.20
연관관계 매핑  (1) 2023.12.19
엔티티 매핑  (0) 2023.08.25
JPA(Java Persistence API)란  (0) 2023.08.17