[Spring Boot2][1] 3. 영속성 관리 - 내부 동작 방식

sorzzzzy·2021년 9월 29일
0

Spring Boot - RoadMap 2

목록 보기
3/26
post-thumbnail

🏷 영속성 컨텍스트

JPA에서 가장 중요한 두가지❗️
1️⃣ 객체와 관계형 데이터베이스 매핑하기

2️⃣ 영속성 컨텍스트

실제 JPA가 내부에서 어떻게 동작하는지는 영속성 컨텍스트를 통해 이해할 수 있다!


➡️ 엔티티 매니저 팩토리가 고객의 요청이 올때마다 앤티티 매니저를 생성함


✔️ 엔티티의 생명 주기

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

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

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

  • 삭제 (removed)
    ➡️ 삭제된 상태


✔️ 영속성 컨텍스트

  • JPA를 이해하는데 가장 중요한 용어
  • “엔티티를 영구 저장하는 환경”이라는 뜻
  • EntityManager.persist(entity);

📌 영속

//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername(“회원1);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
 //객체를 저장한 상태(영속)
em.persist(member);

✔️ 영속성 컨텍스트의 이점

1️⃣ 1차 캐시

 Member member = new Member();
 member.setId("member1");
 member.setUsername("회원1");
 
 //1차 캐시에 저장됨
 em.persist(member);
 
 //1차 캐시에서 조회
 Member findMember = em.find(Member.class, "member1");

➡️ 처음에는 디비에서 가져오지만, 그 이후로는 1차 캐시에서 먼저 조회를 한다!
➡️ 1차 캐시에 있다면 그 캐시에서 데이터를 가져오고 없다면 디비에서 조회!


2️⃣ 동일성(identity) 보장

Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); //동일성 비교 true

➡️ 1차 캐시로 반복 가능한 읽기(REPEATABLE READ) 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공!


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

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();

//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작

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

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


➡️ 쿼리는 persist()가 아닌 commit()을 할 때 날아간다!

try {

            Member member1 = new Member(150L, "A");
            Member member2 = new Member(160L, "B");

            em.persist(member1);
            em.persist(member2);
            System.out.println("================");

            // 데이터를 생성했으니 트랜잭션 커밋
            tx.commit();
        }

⬆️ 실행 시, commit()을 할 때 쿼리가 날아가는 것을 확인!!


4️⃣ 변경 감지(Dirty Checking)

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(); // [트랜잭션] 커밋


➡️ 커밋하면 플러쉬라는 것이 호출되고 엔티티와 스냅샷을 비교한다.
➡️ 1차 캐시에는 사실 스냅샷이라는 것이 존재하는데, 이는 내가 값을 최초로 읽어온 시점을 스냅샷으로 저장해둔다!
➡️ 데이터가 변경이 되는 시점에 JPA가 엔티티와 스냅샷을 비교하고, 업데이트 쿼리를 쓰기지연 SQL 저장소에 만들어둔다
➡️ 마지막으로 그것을 데이터베이스에 반영하고 커밋!



🏷 플러시

플러시란❓❓

➡️ 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 것!
➡️ 영속성 컨텍스트의 쿼리들을 디비로 날려 같은 상태를 만들어 주는 것!


✔️ 플러시 발생 순서

1️⃣ 변경 감지
2️⃣ 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
3️⃣ 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송 (등록, 수정, 삭제 쿼리)


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

1️⃣ em.flush() - 직접 호출
2️⃣ 트랜잭션 커밋 - 플러시 자동 호출
3️⃣ JPQL 쿼리 실행 - 플러시 자동 호출


📌 플러시는!

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


🏷 준영속 상태

나중에 더 자세히 배울 예정이니 이런게 있다~ 정도만 이해하고 넘어가자🤗


준영속 상태란❓❓

( 1차 캐시에 올라간 상태가 바로 영속 상태 = JPA가 관리하는 상태 )
➡️ 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 상황!
➡️ 영속성 컨텍스트가 제공하는 기능을 사용 못함


✔️ 준영속 상태로 만드는 방법

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


빠이티잉~~🤍

profile
Backend Developer

0개의 댓글