이번 글에서는 JPA를 통해서 데이터를 수정하는 방법에 대해서 알아보겠다.
변경감지
방법과 병합
방법이 있고, 결론부터 말하자면 변경감지
방식을 사용하는 것을 권장한다.
본격적으로 시작하기 전에 JPA의 영속성 컨텍스트에 대해서 이해할 필요가 있는데, 예전에 쓴 이 글을 참고하자. 🤭
JPA를 쓰면서 데이터를 수정할 일은 당연히 있을 것이다.
이 때, 수정할 데이터가 영속상태인지 준영속상태인지에 따라서 해야할 것이 달라진다.
먼저, 영속 엔티티를 수정하는 것은 매우 간단하다.
그냥 해당 객체에서 수정하고 싶은 값을 바꿔주면 그것으로 끝이다.
그렇게 하면, 트랜잭션이 커밋될 때, JPA가 알아서 변경사항에 맞게 수정쿼리를 날려준다.
아래의 예시 코드를 참고하자.
// 트랜잭션 시작
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
// 영속 엔티티 수정
User user = userRepository.findById(1L).get();
user.setUsername("hello");
// 트랜잭션 커밋
tx.commit();
entityManager.close();
그렇다면, 준영속 컨텍스트를 수정해야할 때는 어떻게 할까?
비영속 엔티티는 Id와 같은 식별자가 있지만, 영속성 컨텍스트에 없는 객체를 의미한다.
기존의 데이터를 관리자 툴같은 곳에서 수정할 때, 이러한 비영속 엔티티를 서버단에서는 받게 될 것이다.
이 때, 서버에서 할 수 있는 선택지는 2가지가 있다.
하나 하나 살펴보자.
첫번째로 살펴볼 방법은 변경 감지 기능을 이용하는 것이다.
JPA에서도 데이터를 수정할 때에는 이 기능을 사용할 것을 권장하고 있다.
원리는 이러하다.
1. 클라이언트에서 식별자를 포함한 데이터를 넘김
2. 식별자(id)를 통해서 DB에서 데이터 조회 후, 조회된 데이터를 영속화
3. 클라이언트에서 넘어온 값들을 토대로 기존의 데이터를 새로운 데이터로 변경 : 변경점 발생
4. 트랜잭션 커밋
5. JPA에서 변경점들을 확인하고 변경해야할 것에 맞게 DB 쿼리를 실행 : 변경 감지 (Dirty checking)
코드로 한번 살펴보자.
@Transactional
void update(User userParam) {
User user = entityManager.find(User.class, userParam.getId()); // DB의 데이터를 조회해서 영속화
user.setUsername("hello"); // 변경점을 만듬
}
사실 merge가 준영속 상태의 객체를 영속화하는 가장 기본적인 메서드이긴하다.
다만, merge하면 새로운 데이터가 기존의 데이터에 완전히 덮어씌워지게 되는 것이다.
즉, 병합기능으로 정상적으로 데이터를 업데이트 하려면 수정할 데이터만 넘기는 것이 아니라 수정할 Entity전체를 넘겨야한다.
혹시나 실수로 몇몇 값을 빼먹고 보내면 아주... 불상사가 벌어지게 된다. 🤭
왜냐하면, 필드가 없는 것은 null
로 취급하기 때문이다. ㄷㄷ
코드로 한번 살펴보자.
@Transactional
void update(User userParam) {
User user = entityManager.merge(userParam);
}