변경감지와 병합

2024. 1. 6. 15:12·💻 Dev/DB&JPA

JPA에서 데이터를 변경할때의 기본 메커니즘은 변경 감지(Dirty Checking)이다.

개인적으로 신기하다고 생각해서 정리하게 되었다.

아직은 내용이 많이 부족해서 더 채워야 할 것 같다...

 

더티 체킹(Dirty Checking) a.k.a 변경 감지란?

@Transactional
public void updateItem(Long itemId, String name, int price, int stockQuantity) {
    Item findItem = itemRepository.findOne(itemId);
    findItem.setName(name);
    findItem.setPrice(price);
    findItem.setStockQuantity(stockQuantity);
}

위는 pk인 itemId를 조건으로 Item을 조회하고, 조회한 Item 데이터를 수정하는 코드다.

코드만 보면 별도로 데이터베이스에 UPDATE해주지 않는다.

늘 하던대로라면 `itemRepository.update(findItem);`가 존재해야한다.

 

어떻게 가능할까?

JPA에서는 엔티티를 조회하면 해당 엔티티의 조회 상태 그대로 스냅샷을 만들어 놓는다.

그리고 트랜잭션이 끝나는 시점에 이 스냅샷과 비교해서 다른점이 있다면 변경을 감지해 Update Query를 데이터베이스로 전달한다.

 

변경 감지의 대상이 되지 않는 엔티티

but!! 이 변경 감지의 대상이 되지 않는 엔티티가 있다.

 

준영속 엔티티

준영속 엔티티란 영속성 컨텍스트가 더는 관리하지 않는 엔티티를 말한다.

Member member = createMember("userA", "서울","1","11111");
em.persist(member);

 

위처럼 객체를 처음 생성하고 `persist()` 하는 순간 영속상태가 된다.

@Transactional
public void updateItem(Long itemId, String name, int price, int stockQuantity) {
    Item findItem = itemRepository.findOne(itemId);
    findItem.setName(name);
    findItem.setPrice(price);
    findItem.setStockQuantity(stockQuantity);
}

위 코드처럼 이미 itemId가 세팅이 되어있다는 건 이미 DB에 저장되어있다는걸 의미한다.

이 식별자(itemId)가 DB에 이미 존재하면 준영속 엔티티다.

 

준영속 엔티티를 수정하는 2가지 방법

 

1. 변경 감지

@Transactional
void update(Item itemParam) { //itemParam : 준영속 상태의 엔티티
    Item findItem = em.find(Item.class, itemParam.getId()); //조회
    findItem.setPrice(itemParam.getPrice());
}

트랜잭션 안에서 엔티티를 다시 조회하면 영속 상태로 변경한다.

후에 데이터를 수정하면 변경 감지가 동작하기때문에 자동으로 UPDATE가 된다.

 

2. 병합(merge) 사용

@Transactional
void update(Item itemParam) { //itemParam: 준영속 상태의 엔티티
    Item mergeItem = em.merge(item);
}

`merge()`를 수행하여 준영속 상태의 엔티티를 영속 상태로 변경한다.

 

 

병합을 사용해 다시 영속상태가 되는 과정

  1. merge()를 실행한다.
  2. 파라미터로 넘어온 준영속 엔티티의 식별자 값으로 1차 캐시에서 엔티티를 조회한다.
    만약 1차 캐시에 엔티티가 없으면 데이터베이스에서 엔티티를 조회하고, 1차 캐시에 저장한다.
  3. 조회한 영속 엔티티(mergeMember)에 member 엔티티의 값을 채워 넣는다.
    member 엔티티의 모든 값 을 mergeMember에 밀어 넣는다.
    이때 mergeMember의 “회원1”이라는 이름이 “회원명변경”으로 바뀐다.
  4. 영속 상태인 mergeMember를 반환한다.

간단하게 말하면 영속 엔티티(mergeItem)의 값을 파라미터로 들어온 준영속 엔티티(itemParam)값으로 모두 교체한다.

 

 

병합시 조심해야할 점

병합을 사용하면 엔티티의 모든 필드를 다 바꿔버리기 때문에 준영속 상태의 엔티티에 값을 세팅해주지 않은 필드는 null로 바뀔 수도 있다.

가급적이면 merge를 쓰지말고 엔티티를 변경할 때는 항상 변경 감지를 사용하자.

저작자표시 비영리 (새창열림)

'💻 Dev > DB&JPA' 카테고리의 다른 글

[PostgreSQL] 공통 코드 테이블로 REPLACE 지옥 탈출하기  (0) 2023.09.24
단방향, 양방향 연관관계 매핑  (0) 2023.06.23
연관관계가 필요한 이유  (0) 2023.06.22
엔티티 매핑  (0) 2023.06.17
영속성 컨텍스트  (0) 2023.06.16
'💻 Dev/DB&JPA' 카테고리의 다른 글
  • [PostgreSQL] 공통 코드 테이블로 REPLACE 지옥 탈출하기
  • 단방향, 양방향 연관관계 매핑
  • 연관관계가 필요한 이유
  • 엔티티 매핑
현주먹
현주먹
대구 불주먹 출신 현주먹의 개발.log
  • 현주먹
    현주먹의 개발로그
    현주먹
  • 전체
    오늘
    어제
    • 전체글 (167)
      • 👶🏻 CS (15)
        • Operating System (7)
        • DB (5)
        • Data Structure (2)
        • Software Engineering (1)
      • 💻 Dev (54)
        • Java & OOP (24)
        • Spring (4)
        • DB&JPA (6)
        • Test Code (1)
        • JSP & Servlet (13)
        • Etc (6)
      • 💡 Algorithm (25)
        • 인프런 (9)
        • 백준 (16)
      • 🛠 DevOps & Tool (11)
        • Linux (4)
        • AWS (1)
        • Git (2)
        • Etc (4)
      • 📝 끄적끄적 (62)
        • 후기 및 회고 (5)
        • TDD, 클린 코드 with Java 17기 (3)
        • F-Lab (23)
        • 🖥️ 자바의 정석 (11)
        • 📖 Clean Code (3)
        • 항해99 코테 스터디 (11)
        • 📖 가상 면접 사례로 배우는 대규모 시스템 설계 .. (5)
  • 블로그 메뉴

    • 🐈‍⬛ GitHub
    • TIL repository
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 태그

    항해99
    코딩테스트준비
    인프런 특정문자뒤집기
    jsp
    til
    자바의신절판
    코테스터디
    C
    에프랩
    티스토리챌린지
    데브클럽
    F-Lab
    백준
    오블완
    NextSTEP
    자바의정석
    에프랩 후기
    JPA
    인프런 단어뒤집기
    ==와 equals()
    오라클
    개발자멘토링
    TDD 클린 코드 with Java
    PostGreSQL함수
    백준10250
    99클럽
    f-lab 후기
    객체지향
    로또 미션
    개발자취업
  • hELLO· Designed By정상우.v4.10.2
현주먹
변경감지와 병합
상단으로

티스토리툴바