영속성 관리

강한친구·2022년 6월 30일
0

JPA

목록 보기
5/27

영속성 컨텍스트

영속성 컨텍스트는 JPA 이해에 있어서 가장 중요한 용어이다. 엔티티를 영구 저장하는 환경이라는뜻으로, EntityManager.persist(entity)로 표현할 수 있다.

EntityManager 영속성 컨텍스트

영속성 컨텍스트는 논리적 개념이다.

EM을 생성하면 눈에 보이지 않는 PersistenceContext라는 공간이 하난 생긴다.

Entity의 생명주기

  • 비영속
    • 영속성 컨텍스트와 관계가 없는 새로운 상태
  • 영속
    • 영속성 컨텐스트에 관리되는 상태
  • 준영속
    • 컨텍스트에 저장되어있다가 잠시 분리된 상태

코드로 보기

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

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

        try {
        	// 비영속 상태 
            Member member = new Member();
            member.setId(1L);
            member.setName("HelloA");
            
            // 영속 상태 (DB저장을 함) 
            em.persist(member);
            // 준영속 
         	em.detach(member);
            //삭제 
            em.remove(member);

            List<Member> resultList = em.createQuery("select m from Member as m", Member.class)
                    .getResultList();

            for (Member member1 : resultList) {
                System.out.println("name = " + member1.getName());
            }
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
        emf.close();
    }

}

왜 이런 방식을 쓰는가?

공간을 분리하는것으로 다음의 이점을 얻을 수 있다.

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

1차 캐시

Member member = new Member();
member.setId(1L);
member.setName("HelloA");

em.persist(member);
// 이 상태에서 캐시에 저장 

em.find(Member.calss, "member2");
// 캐시 조회

1차캐시에 값을 임의로 저장해놓고 조회가 필요하면 그때 그때 꺼내서 사용한다.

하지만 1차캐시는 한 transcation 안에서만 작동하기때문에 큰 성능적 이득은 없다고 할 수 있다.

동일성 보장

Member findMember1 = em.find(101L);
Member findMember2 = em.find(101L);

101 Id를 가진 member를 찾으면, 두 member가 같은 member인것을 보장해준다. 이는 마치 Java에서 같은 주소를 공유하는것과 동일하다.

트랙잰션 지원하는 쓰기 지원

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

transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
// ------------------------------------------- //
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋

변경감지

기존에 저장되어있는 값을 update할 때, 굳이 query를 안보내도 알아서 변경을 감지해서 처리해준다.

Member member = new Member();
member.setName("HelloA");

//em.persist(member);

이런식으로 해주면 알아서 commit된다.
이는 flush()되는 상태에서 엔티티 스냅샷과 비교해서 update sql을 생성하고 flush하는것이다.

플러시 발생

  1. 변경이 감지된다.
  2. 수정된 엔티티 쓰기 지연 sql 저장소에 저장한다.
  3. 쓰기 지연 sql 저장소 쿼리를 db로 보낸다.

0개의 댓글