인프런 - 스프링 부트와 JPA 활용1 by 김영한 을 기반으로 작성된 글입니다.
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
영속성 컨텍스트가 더는 관리하지 않는 엔티티
영속성 컨텍스트에서 엔티티를 다시 조회한 후에 데이터 수정할 때 사용
준영속 상태의 엔티티를 영속 상태로 변경할 때 사용
준영속 엔티티는 데이터를 변경 해도 DB에 update가 되지 않는다.
💡 이 강의에서 사용하는 병합(merge)은 준영속 엔티티를 수정할 때 사용한다.
DB에 한번 저장 되어 식별자가 존재하는 엔티티는
다시 객체를 생성해도 준영속 엔티티라고 볼 수 있다.
참고 : 책 자바 ORM 표준 JPA 프로그래밍 3.6.5
💻 참고 코드
@Transactional
public Item updateItem(Long itemId, Book param){
//itemId을 기반으로 실제 DB에 있는 영속성 엔티티를 찾아옴
Item findItem = itemRepository.findOne(itemId);
findItem.setPrice(param.getPrice());
findItem.setName(param.getName());
findItem.setStockQuantity(param.getStockQuantity());
return findItem;
itemRepository.save(), EntityManager의 persist, merge 모두 호출 안해도 된다
findItem 은 영속상태 값을 세팅 한 후 @Transactional
에 의해 commit 되어
JPA가 트랜잭션 commit 시점에 변경된 데이터를 DB 에 반영한다
상품 엔티티 item은 식별자가 있으므로 merge를 통해 준영속 엔티티로 변경되지 않는다
@Repository
@RequiredArgsConstructor
public class ItemRepository {
private final EntityManager em;
public void save(Item item){
if (item.getId() == null){
em.persist(item);
} else{
em.merge(item);
}
}
❗ 주의
변경 감지 기능 사용 - 원하는 속성만 선택해서 변경 가능
병합 사용 - 모든 속성이 변경 (모든 필드 교체)
👉 병합 시 값이 없으면 'null' 로 업데이트 할 위험이 있다
예시) 다른 정보는 변경이 가능 하나 '가격'은 바꿀 수 없도록 지정
이 상태에서 merge를 호출 하면 가격은 null로 update 된다(book.setPrice() 값 세팅 X)
💡 엔티티를 변경할 때는 항상 원하는 데이터만 변경하도록 변경 감지 기능을 사용해라
💻 기존 코드
ItemController.java
@Controller
@RequiredArgsConstructor
public class ItemController {
@PostMapping(value = "/items/{itemId}/edit")
public String updateItem(@PathVariable String itemId, @ModelAttribute("form") BookForm form) {
Book book = new Book();
book.setId(form.getId());
book.setName(form.getName());
book.setPrice(form.getPrice());
book.setStockQuantity(form.getStockQuantity());
book.setAuthor(form.getAuthor());
book.setIsbn(form.getIsbn());
itemService.saveItem(book);
return "redirect:/items";
}
}
💻 변경 감지 기능 사용 코드
엔티티를 파라미터로 사용하지 않고 필요한 데이터만 사용 - 유지보수성 향상
ItemService.java
public class ItemService {
@Transactional
public void updateItem(Long itemId, String name, int price, int stockQuantity){
//itemId을 기반으로 실제 DB에 있는 영속성 엔티티를 찾아옴
Item findItem = itemRepository.findOne(itemId);
findItem.setName(name);
findItem.setPrice(price);
findItem.setStockQuantity(stockQuantity);
}
}
ItemController.java
@Controller
@RequiredArgsConstructor
public class ItemController {
@PostMapping(value = "/items/{itemId}/edit")
public String updateItem(@PathVariable Long itemId, @ModelAttribute("form") BookForm form) {
itemService.updateItem(itemId, form.getName(), form.getPrice(), form.getStockQuantity());
return "redirect:/items";
}
}