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

김민희님의 프로필 이미지

작성한 질문수

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

변경 감지와 병합(merge)

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

24.01.25 05:28 작성

·

516

0

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

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

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

라고 이해했습니다.

제가 궁금한 부분은,

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

 

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

답변 2

1

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

2024. 02. 11. 19:37

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

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

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

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

y2gcoder님의 프로필 이미지

2024. 02. 13. 15:30

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

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

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

1

y2gcoder님의 프로필 이미지

2024. 01. 25. 10:10

안녕하세요. 김민희님, 공식 서포터즈 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에도 해당 값 변경을 반영해주는 기능이라고 이해해주는 것이 더 정확했던 것 같습니다.

 

감사합니다.