LUMI_dev
Entity - #4 영속성 컨텍스트의 기능 ★ 2. 쓰기 지연 저장소 (ActionQueue),em.flush();,Dirty Checking (변경 감지) 본문
Entity - #4 영속성 컨텍스트의 기능 ★ 2. 쓰기 지연 저장소 (ActionQueue),em.flush();,Dirty Checking (변경 감지)
luminous_dev 2025. 2. 3. 22:58이것을 공부하기 위해 트랜잭션 공부함
JPA는 트랜잭션처럼 SQL을 모아서 한번에 DB에 반영함
이를 구현하기 위해,
쓰기 지연 저장소로 SQL을 모아두고 있다가 트랜잭션 Commit 후 한번에 DB에 반영
실습) 쓰기 지연 저장소
@Test
@DisplayName("쓰기 지연 저장소 확인")
void test6() {
EntityTransaction et = em.getTransaction();
et.begin();
try {
Memo memo = new Memo();
memo.setId(2L);
memo.setUsername("Robbert");
memo.setContents("쓰기 지연 저장소");
em.persist(memo);
Memo memo2 = new Memo();
memo2.setId(3L);
memo2.setUsername("Bob");
memo2.setContents("과연 저장을 잘 하고 있을까?");
em.persist(memo2);
System.out.println("트랜잭션 commit 전");
et.commit();
System.out.println("트랜잭션 commit 후");
} catch (Exception ex) {
ex.printStackTrace();
et.rollback();
} finally {
em.close();
}
emf.close();
}
em > actionQueue> insertions > executables에 Insert할 memo#2, memo#3 Entity 객체 2개 들어가 있음
트랜잭션 commit 후 actionQueue에 있던 insertions 데이터 사라짐
기록에서도 커밋 전까지는 SQL 요청 없다가 커밋 후 Insert SQL 2개가 순서대로 요청됨
트랜잭션 commit 후의 추가적인 동작
em.flush();
: 영속성 컨텍스트의 변경 내용들을 DB에 반영하는 역할
: 쓰기 지연소의 SQL들을 DB에 요청하는 역할 수행
실습) flush() 동작 확인
@Test
@DisplayName("flush() 메서드 확인")
void test7() {
EntityTransaction et = em.getTransaction();
et.begin();
try {
Memo memo = new Memo();
memo.setId(4L);
memo.setUsername("Flush");
memo.setContents("Flush() 메서드 호출");
em.persist(memo);
System.out.println("flush() 전");
em.flush(); // flush() 직접 호출
System.out.println("flush() 후\n");
System.out.println("트랜잭션 commit 전");
et.commit();
System.out.println("트랜잭션 commit 후");
} catch (Exception ex) {
ex.printStackTrace();
et.rollback();
} finally {
em.close();
}
emf.close();
}
콘솔
em.flush() 메서드가 호출되자 바로 DB 쓰기 지연 저장소의 SQL이 요청됨
트랜잭션이 commit된 후의 SQL 기록은 보이지 않음
→ 이미 쓰기 지연 저장소의 SQL이 요청 되었기 때문에 더 이상 요청할 SQL이 없어서
트랜잭션을 설정하지 않고 .flush() 메서드를 호출하면?
no transaction is in progress라는 메세지와 함께 TransactionRequiredException 오류 발생
데이터 변경 SQL을 DB에 요청 및 반영하기 위해서는 트랜잭션 필요
변경 감지 (Dirty Checking)
Q. 영속성 컨텍스트에 저장된 Entity가 변경될 때마다 Update SQL이 쓰기 지연 저장소에 저장된다면?
→ 하나의 Update SQL로 처리할 수 있는 상황을 여러번 Update SQL을 요청하게 되기 때문에 비효율적
Q. 그러면 JPA는 Update 어떻게 처리?
변경하려는 데이터 있으면 먼저 데이터 조회 ▶해당 Entity 객체 데이터 변경하면 ▶ 자동 Update SQL 생성 ▶ DB 반영
- 영속성 컨텍스트에 Entity 저장할 때 최초 상태 (LoadedState) 저장
- 트랜잭션이 커밋되고 em.flush();가 호출되면 현재 Entity 상태와 저장한 최초 상태 비교
- 변경된 내용이 있으면
- Update SQL 생성
- 쓰기 지연 저장소에 저장 + 모든 쓰기 지연 저장소의 SQL, DB에 요청
- DB의 트랜잭션이 커밋되면서 반영
이러한 과정, Dirty Checking (변경 감지)
실습) Dirty Checking (변경 감지)
@Test
@DisplayName("변경 감지 확인")
void test8() {
EntityTransaction et = em.getTransaction();
et.begin();
try {
System.out.println("변경할 데이터를 조회합니다.");
Memo memo = em.find(Memo.class, 4);
System.out.println("memo.getId() = " + memo.getId());
System.out.println("memo.getUsername() = " + memo.getUsername());
System.out.println("memo.getContents() = " + memo.getContents());
System.out.println("\n수정을 진행합니다.");
memo.setUsername("Update");
memo.setContents("변경 감지 확인");
System.out.println("트랜잭션 commit 전");
et.commit();
System.out.println("트랜잭션 commit 후");
} catch (Exception ex) {
ex.printStackTrace();
et.rollback();
} finally {
em.close();
}
emf.close();
}
entityInstance | Entity 객체의 현재 상태 |
entityEntry > loadedState | 조회했을 때 즉, 해당 Entity의 최초 상태 |
'스파르타 코딩 클럽 | 자바 심화 과정 > Spring Master (입문 주차)' 카테고리의 다른 글
SpringBoot JPA_#1-1. SpringBoot 환경에서의 JPA_build.gradle 및 application.properties 설정, Entity 클래스 (0) | 2025.02.04 |
---|---|
Entity- #5. Entity의 상태 (0) | 2025.02.03 |
Entity - #4 영속성 컨텍스트의 기능 1. 1차 캐시 (0) | 2025.02.03 |
Entity - #3. JPA 트랜잭션 (데이터 변경 SQL을 DB에 요청 및 반영하기 위해서는 트랜잭션 필요) (1) | 2025.02.03 |
persistence.xml에 넣은 설정 + gradle config 열기 + jpa hibernate 설정 (1) | 2025.02.02 |