Spring

변경 감지와 병합(merge)

JUNGKEUNG 2022. 9. 29. 00:11

변경 감지와 병합(merge)

JPA는 영속성 context에 테이블 형태의 1차 캐시를 두고 엔티티를 저장해서, Transaction commit 시, 1차 캐시의 영속된 값과 현재 entity값을 비교하여 변경이 된 것을 알아서 적용해준다.

 

 

 

준영속 상태

  • 영속 상태였다가 더는 영속성 컨텍스트가 관리하지 않는 상태
  • 영속성 컨텍스트로부터 분리된 상태

 

 

 

준영속 상태를 만드든 3가지 방법

1. em.detach(entity) : 특정 엔티티만 준영속 상태로 전환

2. em.clear() : 영속성 컨텍스트를 완전히 초기화

3. em.close() : 영속성 컨텍스트를 종료

 

 

 

준영속 엔티티

  • 영속성 컨텍스트가 더는 관리하지 않는 엔티티를 말한다
  • 엔티티의 데이터를 가지고 있는 클라이언트 사이드로 넘기기 위한 객체

 

 

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

변경 감지 기능 사용

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

병합(merge) 사용

@Transactional
public void update(Item itemParam) {
	Item mergeItem = em.merge(item);
    //item은 준영속, mergeItem은 영속 상태
}

변경 감지 기능을 사용하면, 원하는 속성만 선택해서 변경할 수 있지만, 병합을 사용하면 모든 속성이 변경된다. 모든 필드를 교체하기 때문에 병합 시 해당하는 값이 없다면 null로 업데이트할 위험이 있다.

실무에서는 업데이트 기능이 매우 제한적이다. 병합 시 값이 없다면 null 로 업데이트하는 문제를 해결하려면, 변경 폼 화면에서 모든 데이터를 항상 유지해야 하는데 보통 변경 가능한 데이터만 노출하기 때문에 병합을 사용하는 것은 매우 번거롭다. 때 문에 웬만하면 변경 감지를 활용하는 편이 좋다.

 

 

가장 좋은 해결 방법

엔티티를 변경할 때는 항상 변경 감지를 사용하세요

  • 컨트롤러에서 어설프게 엔티티를 생성하지 말자
  • 트랜잭션이 있는 서비스 계층에 식별자(id)와 변경할 데이터를 명확하게 전달하자
  • 트랜잭션이 이쓴 서비스 계층에서 영속 상태의 엔티티를 조회하고, 엔티티의 데이터를 직접 변경하자
  • 트랜잭션 커밋 시점에 변경 감지가 실행된다.

'Spring' 카테고리의 다른 글

연관관계 매핑 기초  (1) 2022.10.19
@Transactional  (0) 2022.09.29
빈 생명주기 콜백  (0) 2022.07.30
의존관계 자동 주입  (0) 2022.07.24
싱글톤 컨테이너  (0) 2022.07.10