[Spring] Entity 수정은 변경 감지를 활용하자

bluewhale·2021년 5월 26일
2

Spring

목록 보기
6/9
post-thumbnail

이 글은 김영한 님의 실전! 스프링 부트와 JPA 활용-1 강의를 참고하여 작성한 글입니다.

변경 감지

스프링에서 EntityManger의 주요 기능 중 하나로 Dirty Check가 있다.
EntityManger는 현재 트랜잭션에서 영속성 컨텍스트에 포함되어 있는 Entity객체에 수정이 발생할 경우, 트랜잭션이 커밋되는 시점에 내부적으로 UPDATE 쿼리를 생성하여 전달한다.

기본적으로 EntityManagerfind()createQuery() 메서드를 통해 조회는 Entity 객체는 영속성 컨텍스트에 포함된다. 따라서, persist() 메서드를 명시적으로 호출하지 않아도 된다.

그러나, EntityManager는 준영속 상태(Detached)의 Entity에 대해서는 Dirty Check를 수행하지 않는다. 만약, 사용자가 폼 정보를 기반으로 새로운 Entity 객체를 생성한다면 해당 객체는 준영속 상태에 해당되어 Dirty Check가 수행되지 않는다.

그러므로 준영속 상태에 놓인 Entity 객체를 수정하기 위해서는 EntityManager에서 find()createQuery()를 호출하여 영속 상태의 객체를 불러와 데이터를 수정하거나, 해당 Entitymerge하여 영속 상태로 변경하여 Dirty Check가 작동하도록 해야한다.

merge

merge()는 준영속 상태에 있는 Entity를 영속성 컨텍스트에 다시 편입시키는 메서드이다. merge()를 호출하면 Entity가 영속 상태가 되며, 변경 사항 감지 시, 모든 필드에 대한 업데이트가 발생하기 때문에 필드가 의도치않게 null에 노출될 수 있는 위험이 있다. 또한, 실제 데이터 수정이 발생하는 영역과 변경 사항이 적용되는 영역이 분리되어 있어, 변경 사항을 추적하기 어렵다. 그러므로, merge() 사용을 지양하자.

예시

다음은 준영속 상태의 Entity를 변경감지를 통해 업데이트 하는 코드이다.


@Service
@AllArgsConstructor
public class ItemService {

    ItemRepository itemRepository;

    @Transactional
    public Item updateItem(Long itemId, Item param) {
    	// findResult 객체는 영속 상태에 있으므로 변경감지가 동작한다
        Item findResult = itemRepository.findOne(itemId).get();
        
        // param은 준영속 상태의 Entity 객체이다 
        findResult.setName(param.getName())
        findResult.setPrice(param.getPrice())
        
        // param은 여전히 준영속 상태이다.
        // 하지만, 반환되는 findResult는 영속 상태의 엔티티이다.
        return findResult
    }
}
profile
안녕하세요

1개의 댓글

comment-user-thumbnail
2022년 12월 28일

엔티티에 setter 가 없는 경우는 어떻게 하나요?

답글 달기