JPA에서 엔티티 수정 시 사용되는 방식은 두 가지가 있다.
- Dirty checking(변경 감지)
- Merge(병합)
Dirty checking
: 영속성 컨텍스트에서 관리되는 엔티티의 변경 사항을 추적하고, 트랜잭션 커밋 시점에 변경 사항이 있는 엔티티를 데이터베이스에 반영하는 방식이다.
Merge 방식
:준영속 상태인 엔티티를 다시 영속 상태로 변경하면서 모든 속성을 변경하고 데이터베이스에 반영한다.
우선, 물품의 정보를 수정하는 과정을 보자.
1. 수정 버튼을 누르면, 상품 수정 폼을 보여주는 페이지로 이동
상품 목록 페이지에 수정 버튼이 있고, 수정 버튼을 누르면 "/items/{id}/edit"으로 이동한다고 하자.
그럼 해당 url로의 get요청을 처리하는 코드가 필요하겠다.
@GetMapping("/items/{itemId}/edit")
public String updateItemForm(@PathVariable("itemId") Long itemId, Model model){
Book item = (Book) itemService.findOne(itemId);//캐스팅하면 좋지 않으나 예제니까..
BookForm form = new BookForm();
form.setId(item.getId());
form.setName(item.getName());
form.setAuthor(item.getAuthor());
form.setIsbn(item.getIsbn());
form.setPrice(item.getPrice());
form.setStockQuantity(item.getStockQuantity());
model.addAttribute("form", form);
return "items/updateItemForm";
}
url의 PathVariable로 itemId를 받으면, 데이터베이스에서 해당 itemId에 해당하는 엔티티를 꺼내온다.
(이 예제에서는 item이 Book이라고 가정함)
수정 폼에는 기존의 값들이 입력되어 있어야 하니까,
가져온 엔티티에서 값을 뽑아내서 form객체를 만들고, form을 넘겨준다.
2. 상품 수정 폼에서 정보를 수정하고 submit 버튼을 선택
3. 해당 POST 요청을 처리
POST요청을 받아서, 데이터베이스에 있는 내용을 수정하면 되겠다.
@PostMapping("/items/{itemId}/edit")
public String updateItem(@ModelAttribute("form") BookForm form, @PathVariable("itemId") Long itemId){
itemService.updateItem(itemId,form.getName(),form.getPrice(),form.getStockQuantity());
return "redirect:/items";
}
itemService를 이용해서 수정하면 되겠다.
근데 itemService.updateItem은 어떻게 동작하나?
그건 본문에 적겠다.
Dirty checking
(ItemService.java)
@Transactional
public void updateItem(Long itemId, String name, int price, int stockQuantity){
Item findItem = itemRepository.findOne(itemId);//DB에 있는 실제 값
//아래의 코드들은 findItem.change()같은 메소드를 따로 만들어 처리하는것이 좋다.
// findItem.setPrice(price);
// findItem.setStockQuantity(stockQuantity);
// findItem.setName(name);
findItem.change(name,price,stockQuantity);
//JPA는 영속성 컨텍스트의 변경을 감지하고 업데이트쿼리를 자동으로 보내 처리함
}
itemId를 받아서 영속성 컨텍스트 findItem을 가져오고, findItem의 속성들을 변경해준다.
영속성 컨텍스트는 JPA가 관리하므로 값이 변경되면 트랜잭션 커밋 시점에 변경사항이 있는 데이터를 데이터베이스에 반영해준다.
이 방식을 이용하면 변경이 필요한 속성만 수정할 수 있다.
Merge
@Transactional
void update(Item itemParam) { //itemParam: 파리미터로 넘어온 준영속 상태의 엔티티
Item mergeItem = em.merge(itemParam);
}
병합의 과정은 다음과 같다.
1. 준영속 엔티티의 식별자 값으로 영속 엔티티를 조회
2. 영속 엔티티의 모든 속성을 준영속 엔티티의 속성으로 변경
3. 트랜잭션 커밋 시에 변경이 감지되어 데이터베이스에 반영
병합은 모든 속성을 변경하게 되는데, 이때문에 병합시 값이 없으면 속성값이 null로 변경될 수 있다.
'웹개발 > SpringBoot' 카테고리의 다른 글
로그인 여부에 따라 바뀌는 로그인/로그아웃 버튼 만들기 (0) | 2023.05.27 |
---|---|
@RequestBody를 적어야 됐던 일 (1) | 2023.05.18 |
JPA, Spring Data JPA (0) | 2023.03.21 |
의존성 주입(DI), 스프링 빈과 의존관계 (0) | 2023.03.19 |
빌드하고 실행하기 (0) | 2023.03.18 |
댓글