변경감지와 병합 ✨

·2023년 5월 27일
0

준영속 엔티티?

데이터베이스에 한번 다녀온,, 즉 식별자가 데이터베이스 안에 있는 경우(ex. 이미 만들어진 게시글 db를 수정할때, 해당 db는 준영속 엔티티)
jpa가 식별할 수 있는 Id가 있기 때문에 영속성 컨텍스트가 더이상 관리하지 않음.

@PostMapping("items/{itemId}/edit")
    public String updateItem(@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";
    }

준영속 엔티티의 문제?

jpa가 더이상 관리하지 않음.
따라서 아무리 값 변경을 시켜도 jpa가 db를 update 해주지 않음

그렇다면 어떻게 수정할 수 있을까?

  1. 변경감지 == dirty checking
    ① service에서 @Transactional
    ② itemRepository에서 id를 기준으로 item을 찾은 후
    ③ 찾은 item에 새로운 변수 set 처리
    ④ 그 다음 save, persis, merge 호출할 필요 없음.
  • 왜 ? id를 기준으로 item을 찾은 후 <- 얘는 영속 상태가 됨
    따라서 값을 세팅한 다음에 transactional을 통해 커밋이 됨.
    커밋이 된 후 jpa는 flush를 날림 (=영속성 컨텍스트 변경내용을 DB에 반영하는 것)
    @Transactional
    public void updateItem(Long itemId, Book param){
        Item findItem = itemRepository.findOne(itemId);
        findItem.setPrice(param.getPrice());
        .... (대충 findItem 에 값을 다 세팅했다고 치고)

        // 여기까지만 하면 jpa가 flush를 날려서 변경 완료.
    }
  1. 병합(merge) 사용
    병합 ? 준영속상태 엔티티를 영속상태로 변경할때 사용하는 기능
    위에 변경감지를 위해 만든 코드를 jpa가 처리 해줌.
    ① merge() 실행 -> 1차로 캐시에서 조회, 없으면 db에서 조회 후 캐시에 저장
    ② 파라미터로 넘어온 준영속 상태 데이터를 캐시에서 찾은 영속상태 데이터에 밀어넣음(set 처리)
    ③ 바꿔치기 된 데이터를 반환해줌

이때 em.merge(item)에서 item은 영속상태로 변하지 않기 때문에
만약 변경된 데이터를 쓰고 싶다면
Item m = em.merge(item) 으로 처리 후, m 을 사용해야함.

  public void save(Item item){
        if(item.getId() == null) {
            em.persist(item);
        } else{
            em.merge(item); // similar with update
        }
    }

병합에서 조심해야하는 것

  • 변경감지 기능을 사용하면 원하는 속성만 선택해서 변경 가능하지만
  • 병합을 사용하면 모든 속성이 다 변경됨.
  • if. 병합 시 값이 없으면 'null'로 업데이트 해버림

🎈결론 : 가급적이면 병합을 쓰기보다는 변경 감지를 쓰자!

0개의 댓글