정말 중요한 내용이다 100% 이해하고 넘어가자

@Test
    public void updateTest() {
        Book book = em.find(Book.class, 1L);

        //TX
        book.setName("asfsadf");

        //TX commit
    }

위와 같은 테스트 코드에서 트랜잭션에서는 book.setName(”asfsadf");으로 이름을 바꿔주고 트랜잭션이 커밋이 되면 jpa가 변경된 사항에 대해 찾아서 자동으로 업데이트 쿼리를 작성하고 DB에 반영한다.

이러한 기능을 더티체킹(변경감지) 라고 한다.

1. 준영속 엔티티

영속성 컨텍스트가 더는 관리하지 않는 엔티티이다.

ex)

 @PostMapping(value = "/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";
    }

위 코드는 사용자가 주문한 사항을 수정하는 예제코드이다. 사용자가 업데이트할 사항을 입력하고 submit 하게되면 BookForm을 통해 데이터가 넘어오게 된다. 개발자는 Book 객체를 생성하고 폼에서 받아온 데이터를 set을 통해 수정하려하는데, 이 때 Book은 이미 세팅이 되어있는 상태이다. 이미 jpa에서 한번 처리가 된 상태라는 말이다. 이렇게 DB에 한번 저장이 되고 식별자가 정확히 DB에 존재하는 상태인 객체를
준영속 상태의 객체(준영속엔티티) 라고 한다. 준영속 엔티티는 변경감지가 실행되지 않는다.

<aside> 💡

itemService.saveItem(book) 에서 수정을 시도하는 Book 객체다. Book 객체는 이미 DB에 한번 저장되어서 식별자가 존재한다. 이렇게 임의로 만들어낸 엔티티도 기존 식별자를 가지고 있으면 준영속 엔티티로 볼 수 있다.

</aside>

2. 준영속 엔티티를 수정하는 2가지 방법

2-1. 변경감지

@Transactional
void update(Item itemParam) { //itemParam: 파리미터로 넘어온 준영속 상태의 엔티티
 Item findItem = em.find(Item.class, itemParam.getId()); //같은 엔티티를 조회한
다.
 findItem.setPrice(itemParam.getPrice()); //데이터를 수정한다.
}

영속성 컨텍스트에서 엔티티를 다시 조회한 후에 데이터를 수정하는 방법 트랜잭션 안에서 엔티티를 다시 조회, 변경할 값 선택 → 트랜잭션 커밋 시점에 변경 감지가 동작해서 DB에 UPDATE SQL 실행 find()를 사용하면 다시 영속성 컨텍스트에 등록된다.

2-2. 병합(merge)

@Transactional
    public void updateItem(Long itemId, Book param) {
        Item findItem = itemRepository.findOne(itemId);
        findItem.setPrice(param.getPrice());
        findItem.setName(param.getName());
        findItem.setStockQuantity(param.getStockQuantity());
    }
public void save(Item item) {
        if(item.getId() == null) {
            em.persist(item); // 영속성 컨텍스트에 저장 이후 flush 혹은 commit 시에 db에 저장
        } else {
            em.merge(item); // 엔티티 수정 시 기존 엔티티와 병합(값을 바꿔버림)
        }
    }

준영속 상태의 엔티티를 영속 상태로 변경 할 때 사용하는 기능이다. 아래 코드에 merge로 넘긴 item파라미터의 값으로 위 코드의 엔티티에서 변경하는 값들을 다 바꿔버린다. 바꾸는게 가능해지니 트랜잭션 커밋 시점에 DB에 반영이 된다. 영속성 컨텍스트에서 itemId로 db나 영속성컨텍스트를 조회해서 같은 식별자로 item을 찾는다. 그 후에 파라미터로 넘어온 Book param