본문 바로가기

BackEnd/JPA

[JPA] 영속성 컨텍스트(Persistence Context)란?

영속성 컨텍스트란?

 영속성 컨텍스트란 "엔티티를 영구적으로 저장하는 환경"을 의미하며 눈에 보이지 않는 논리적인 개념이다.

 엔티티 매니저를 통해 영속성 컨텍스트에 접근이 가능하다. 

public class JpaMain {    
	public static void main(String[] args) {        
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");        
		EntityManager em = emf.createEntityManager();                
		...    
	}
}

 

엔티티의 생명주기

  • 비영속 (new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
    // 객체를 생성한 상태(비영속)
    Member member = new Member();
    member.setId("member1");
    member.setUsername("회원1");​
  • 영속 (managed) : 영속성 컨텍스트에 관리되는 상태
    // 객체를 생성한 상태
    Member member = new Member();
    member.setId("member1");
    member.setUsername("회원1");
    em.persist(member);
  • 준영속 (detached) : 영속성 컨텍스트에 저장 되었다가 분리된 상태이며 영속성 컨텍스트의 제공기능을 사용 못한다.
    em.detach(member);  // 특정 엔티티만 준영속 상태로 전환
    em.clear();         // 영속성 컨텍스트를 완전히 초기화
    em.close();         // 영속성 컨텍스트를 종료​
  • 삭제(removed) : 엔티티를 삭제하여 엔티티매니져에 값이 없는 상태
    //삭제 대상 엔티티 조회
    Member memberA = em.find(Member.class, "memberA"); 
    // 객체를 삭제한 상태(삭제)
    em.remove(member);​

영속성 컨텍스트의 장점

  • 1차 캐시
    Member member = new Member();member.setId("member1");
    member.setUsername("회원1"); 
    em.persist(member);  // 1차 캐시에 저장됨
    Member findMember1 = em.find(Member.class, "member1"); // 1차 캐시에서 조회(디비커넥션X)
    Member findMember2 = em.find(Member.class, "member2"); // 데이터베이스에서 조회​
  • 동일성(identity)  보장 : 영속 엔티티의 동일성 보장
    Member a = em.find(Member.class, "member1");
    Member b = em.find(Member.class, "member1");
    System.out.println(a == b) // 동일성 비교 true​​​
  • 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    //엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
    tx.begin(); // [트랜잭션] 시작
    
    em.persist(memberA);
    em.persist(memberB);
    //여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
    
    //커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
    tx.commit(); // [트랜잭션] 커밋​​
  • 변경 감지(Dirty Checking) : 영속 엔티티의 데이터 수정이 확인되면 데이터베이스 업데이트
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin(); // [트랜잭션] 시작
    
    // 영속 엔티티 조회
    Member memberA = em.find(Member.class, "memberA");
    
    // 영속 엔티티 데이터 수정
    memberA.setUsername("hi");
    memberA.setAge(10);
    
    transaction.commit(); // [트랜잭션] 커밋​​​

플러시( flush)

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

 플러시 발생

  • 변경 감지
  • 수정된 엔티티 쓰기 지연 SQL 저장소에 등록한다.
  • 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송한다.

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

  • em.flush() 를 직접 호출한다.
  • 트랜잭션 커밋하여 플러시를 자동 호출한다.
  • JPQL 쿼리를 실행하여 플러시를 자동 호출한다.
    // JPQL 쿼리 실행 시 플러시가 자동으로 호출되는 이유
    em.persist(memberA);
    em.persist(memberB);
    em.persist(memberC);
    
    // 중간에 JPQL 실행
    // JPQL이 실행되기 전 memberA ~ C 의 값이 저장되어야 정상적인 목록을 불러올 수 있기 때문이다.
    query = em.createQuery("select m from Member m", Member.class);
    List<Member> members = query.getResultList();​​

 플러시 모드 옵션

  • em.setFlusMode(FlusModeType.COMMIT)
    - FlushModeType.AUTO : 커밋이나 실행할 때 플러시 (기본값)
    - FlushModeType.COMMIT : 커밋할 때만 플러시