public void save(Item item){
if(item.getId() == null) {
em.persist(item);
} else {
em.merge(item);
}
JPA의 경우 해당 객체가 변경이 있으면(JPA의 변경 감지 = dirty checking)
자동으로 DB와 동기화 시켜주는 것으로 알고 있는데 merge는 무엇일까?
준영속 엔티티
준영속 엔티티는 영속성 컨테스트에서 관리하지 않는 엔티티를 부르는 것으로,
트랜잭션에서 벗어나거나 특정 메서드 호출 (영속성 컨텍스트에서 떼어내거나, 영속성 컨테스트를 초기화하거나)
등의 이유로 만들어 지는데, 아래의 Book 또한 준영속 엔티티이다.
@PostMapping("items/{itemId}/edit")
public String updateItem(@ModelAttribute("form") BookForm form) {
Book book = new Book();
book.setId(form.getId());
book.setName(form.getName());
book.setIsbn(form.getIsbn());
book.setAuthor(form.getAuthor());
book.setStockQuantity(form.getStockQuantity());
book.setPrice(form.getPrice());
itemService.saveItem(book);
return "redirect:/items";
}
Form에 입력된 사용자 값을 ModelAttribute로 받고 Book을 생성 해줬을 뿐 1차 캐시에 넣는 행위를 안한 상태.
이때, 준영속 엔티티를 영속성 컨테스트에서 관리하게 포함시키도록 하는 방법이 merge이다.
Merge
EntityManager의 merge 메서드를 호출하게 되면 식별자 키를 이용해서
영속성 컨테스트 -> DB에서 찾는다.
해당되는 식별자 키의 값이 있으면 DB에 저장 되어있는 객체의 값을 치환 후 반환 해주고
값이 없으면 새로운 값으로 엔티티를 반들어 영속 상태인 엔티티로 반환해준다.
매개 변수로 넣은 객체(item)의 경우 그대로 준영속 엔티티 이며 merge() 호출 시 반환 값인
Item managedItem = em.merge(item)
managedItem이 영속 컨테스트에 의해 관리되는 엔티티 이다.
Merge 사용 시 주의점
- 필드가 존재하지 않으면 누락될 수 있음
- merge()는 준영속 엔티티의 모든 필드 값을 영속성 컨텍스트가 갖고 있는 엔티티에 복사해 넣습니다.
- 복사 과정에서 엔티티 내부에서 관리되지 않는 필드나 지연 로딩 등을 주의 깊게 확인해야 합니다.
- 또한, 준영속 엔티티에 null 필드가 있으면, 기존 영속 엔티티의 해당 필드가 null로 덮어씌워질 수 있으므로 주의가 필요합니다.
위와 같은 주의점이 존재하기 때문에 중영속 엔티티를 이용해 em.find()와 같은 메서드를 이용해 영속성 엔티티를 가져와서 적절한 메서드를 이용해 값을 변경 감지로 수정하게 하도록 하는 것이 좋다.
@PostMapping("items/{itemId}/edit")
public String updateItem(@ModelAttribute("form") BookForm form) {
//PathVariable 사용 가능
Book book = itemService.findItem(form.getItemId());
book.updatedValues(form.getPrice(),form.getStockQuantity());
return "redirect:/items";
}
출처 관련 : https://tan-sog.tistory.com/90
'DB > JPA' 카테고리의 다른 글
[JPA] 상속관계 매핑 (0) | 2025.02.10 |
---|---|
[JPA] 다양한 연관관계 매핑 (0) | 2025.02.09 |
[JPA] JPA를 공부하며 (0) | 2025.02.04 |
[JPA] 객체의 연관관계와 연관관계 주인 (0) | 2025.01.28 |
[JPA] 엔티티 매핑2 - 기본 키 매핑 (0) | 2025.01.06 |