반응형
변경 감지와 병합(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 |