[Spring Boot2][1] 3. 영속성 관리 - 내부 동작 방식
🏷 영속성 컨텍스트
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()
- 영속성 컨텍스트를 종료
빠이티잉~~🤍
Author And Source
이 문제에 관하여([Spring Boot2][1] 3. 영속성 관리 - 내부 동작 방식), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@sorzzzzy/Spring-Boot21-3.-영속성-관리-내부-동작-방식저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)