인프런 커뮤니티 질문&답변

김민희님의 프로필 이미지

작성한 질문수

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

변경 감지와 병합(merge)

준영속 상태의 객체인 이유, 영속 상태의 객체인 이유

작성

·

574

0

안녕하세요. 강의 내용과 관련하여 질문이 있어 글 남깁니다.

강의에서 10:00 정도에 변경 감지 방법에 대해 설명하시는 부분입니다.

트랜잭션 상에서 엔티티를 다시 조회하여 내용을 변경하면 이 엔티티는 영속 상태이므로 변경 감지가 된다. 따라서 save() 를 하지않아도 알아서 변경 감지되어 DB에 update된다.

라고 이해했습니다.

제가 궁금한 부분은,

  1. itemRepository.findOne(itemId); 부분에서 엔티티를 조회하는데, 이 엔티티는 원래 준영속 상태의 엔티티였고, findOne() 을 함으로써 다시 영속성 컨택스트에 들어온 건가요? 아니면 생성된 때부터 지금까지 죽 영속 상태였나요?
    강의의 맥락상, 지금 준영속 객체를 변경하는 방법에 대해 배우고 있으니 전자일 것이라고 생각했습니다.

 

  1. 만약 제가 생각한대로 준영속 상태에서 변경된 것이 맞다면, merge와 역할 자체는 같은게 맞나요? 물론 디테일한 로직이 좀 다르지만, 역할 자체만 보면 merge또한 준영속 객체를 기발으로 영속 객체를 만들어 반환해주는 거고, 변경 감지 기법도 findOne()을 통해 준영속 객체를 영속 객체로 다시 만들어주는 것이니까요.
    이 둘의 차이점은 객체가 통째로 갈아치워지느냐, 부분 수정이 가능하냐 이것 정도만 있다, 라고 이해해도 될까요?

답변 2

1

김민희님의 프로필 이미지
김민희
질문자

지금 단계에서는 트랜잭션 밖으로 나가서 영속성 컨텍스트의 관리를 받지 않게 된 엔티티 정도로만 이해하고 진행하셔도 무방합니다!

-> 기본편에서 공부했던 걸 생각해보면, 영속 상태 객체가 준영속이 되는 경우는
1. em.detach()로 영속성 컨텍스트에서 떼어냈을 때
2. em.clear() 로 영속성 컨텍스트 내부를 초기화했을 때
3. em.close() 로 영속성 컨텍스트를 닫았을 때

이렇게 세가지로 배웠던 것 같습니다.

영속 객체에서 준영속 객체가 되는 경우는 이 세가지 경우만 가능하고, 트랜잭션이 commit 된다고 영속성 컨텍스트의 객체들이 준영속 상태가 되는건 아니라고 이해했었는데, 제가 잘못 이해할 걸까요?

기본적으로 스프링 컨테이너에서는 트랜잭션 범위와 영속성 컨텍스트의 생존 범위가 같습니다. (나중에 OSIV를 배우시면 예외적인 경우가 있습니다!) 트랜잭션이 걸린 메서드가 종료된 후 반환된 객체는 영속성 컨텍스트 밖으로 나온 객체이므로 준영속 객체라고 볼 수 있습니다! 위에서 언급해주신 3번과 같다고 생각하시면 될 것 같습니다 :)

트랜잭션이 커밋됨과 동시에 트랜잭션이 종료되고 영속성 컨텍스트 내에서 벗어난 객체기 때문에 준영속 상태가 되었다고 생각해주시면 감사하겠습니다!

영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 강의의 OSIV 부분을 복습해보시거나 본 강의와 동명의 책인 자바 ORM 표준 JPA 프로그래밍13장 웹 애플리케이션과 영속성 관리 > 13.1 트랜잭션 범위의 영속성 컨텍스트 부분을 읽어보시는 것을 권해드립니다!

1

안녕하세요. 김민희님, 공식 서포터즈 y2gcoder입니다.

트랜잭션 상에서 엔티티를 다시 조회하여 내용을 변경하면 이 엔티티는 영속 상태이므로 변경 감지가 된다. 따라서 save() 를 하지않아도 알아서 변경 감지되어 DB에 update된다.

정확하게 이해하신 것 같습니다. 이 문장을 토대로 아래의 질문에 답변을 드리고자 합니다.

1.

/**
* 영속성 컨텍스트가 자동 변경 */
@Transactional
public void updateItem(Long id, String name, int price, int stockQuantity) {
         Item item = itemRepository.findOne(id);
         item.setName(name);
         item.setPrice(price);
         item.setStockQuantity(stockQuantity);
}

이 부분에서 updateItem() 전체가 트랜잭션 내에 있고, 그 말은 영속성 컨텍스트 환경이라는 뜻입니다. 그 속에서 파라미터로 전달받은 id를 사용해 findOne(id)해온 item 객체는 엔티티 매니저를 사용해 트랜잭션 상에서 조회해왔기 때문에 영속 상태의 엔티티입니다. 그리고 영속상태의 엔티티기 때문에 변경감지가 가능합니다. 그래서 위의 코드에서 다시 itemRepository.save(item); 코드를 추가해줄 필요가 없는 것입니다.

준영속 상태는 앞쪽 강의자료에도 나와있지만 영속성 컨텍스트가 더이상 관리하지 않는 엔티티를 말합니다. 이는 트랜잭션 바깥으로 나간 엔티티도 포함됩니다.

image이는 앞의 내용과 강의자료를 같이 복습해주시면 도움이 될 것 같습니다. 또한 영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 강의의 섹션 3. 영속성 관리 - 내부 동작 방식 을 학습하시면 좀 더 잘 이해가 되실 것입니다. 지금 단계에서는 트랜잭션 밖으로 나가서 영속성 컨텍스트의 관리를 받지 않게 된 엔티티 정도로만 이해하고 진행하셔도 무방합니다!

2.

merge는 준영속 상태의 엔티티를 영속상태로 변경할 때 사용하는 기능이 맞습니다! 그 과정에서 준영속 엔티티의 값으로 영속 엔티티의 값들이 전부 바뀌기 때문에 값을 변경할 수 있습니다 :)

image개인적으로 변경감지는 원래 영속 상태의 엔티티의 값을 수정해서 트랜잭션 커밋 시점에 DB에도 해당 값 변경을 반영해주는 기능이라고 이해해주는 것이 더 정확했던 것 같습니다.

 

감사합니다.