JPA
[JPA] update가 왜 안되는거지..? (detached to persistent)
코리늬
2020. 7. 21. 23:54
문제의 메소드
@PostMapping("/settings/profile")
public String updateProfile(@CurrentUser Account account, @Valid Profile profile, Errors errors, Model model){
if(errors.hasErrors()){
model.addAttribute(account);
return "/settings/profile";
}
//데이터 변경 작업은 서비스 쪽에 위임
accountService.updateProfile(account, profile);
//사용자의 form submit이 다시 일어나지 않도록 redirect
return "redirect:/" + "settings/profile";
}
분명히 updateProfile을 서비스단에서 @Transactional 의 관리하에 업데이트를 하였는데 실제로는 업데이트가 되지않았다..!!
왜냐하면, 현재 Account 파라미터는 앞서 세션에서 사용했던 Principal 인증정보이기 때문에 Detached
상태이다.
- Transaction이 끝난지 오래다.
그래서 값을 올바르게 넣었음에도 변경이 되지 않는것이다.
정답을 알려줘..!
public void updateProfile(Account account, Profile profile) {
account.setBio(profile.getBio());
account.setUrl(profile.getUrl());
account.setOccupation(profile.getOccupation());
account.setLocation(profile.getLocation());
accountRepository.save(account);
}
Detached 상태인 account객체를 save를 해주면, 결과적으로 merge
가 동작하여 persistent
상태가 되기 때문에 업데이트가 정상적으로 된다.
save()메소드의 내부 로직을 보면
@Transactional
public <S extends T> S save(S entity) {
if (this.entityInformation.isNew(entity)) {
this.em.persist(entity);
return entity;
} else {
return this.em.merge(entity);
}
}
새로운 entity일 경우 해당 entity를 영속 상태로 만들고 그 엔티티를 리턴하지만, 그렇지 않을경우 merge를 하게된다.
그래서 업데이트가 정상적으로 되는것이다.
의문점
어,, 그럼 이게 결국 dirtyChecking이 된건가??
최종적으로 업데이트 된 모습이 나는 dirtyChecking과 상당히 유사하다고 생각이 되어서 매우 헷갈렸다.
한참을 찾아본 끝에 답을 얻을 수 있었다.
- dirtyChecking은
persistent
상태에 있는 엔티티에 대해서만 적용된다. - 따라서
detached
상태인 account는 dirtyChecking으로 인한 업데이트가 아니고 merge에 의한 업데이트가 맞는것이다.