save()
@Transactional
@Override
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Entity must not be null.");
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
}
save는 기본적으로 트랜잭션을 가지고 있고 save 했을때 해당 엔티티가 새로운 엔티티인지 체크를 한다.
체크 결과에 따라 새로운 엔티티면 persist, 존재하는 엔티티라면 merge를 한다.
이 둘의 차이는 다음과 같다.
persist는 처음 생성된 엔티티를 영속화한다.
merge는 준영속성상태 또는 비영속상태의 엔티티를 다시 영속화한다.
merge의 동작 방식
- merge를 실행한다.
- 파라미터의 entity의 식별자 값으로 1차 캐시에서 entity를 조회한다.
- 만약 없다면 db에서 조회해 저장한다.
- 파라미터의 값으로 모든 값을 변경한 후 저장한다.
- 커밋되면 해당 변경점을 확인하고 update를 db에 반영한다.
언제 사용하면 좋을까?
save() 경우 새로운 entity를 저장할때 사용하면 좋다.
하지만 새로운 entity가 아닌경우 merge를 사용하게 되는데 merge의 동작방식에서 알 수 있듯이 준영속, 비영속 상태의 엔티티에서 merge는 selet를 이용해 한번 조회한 후 동작하기에 쿼리가 추가적으로 나가 낭비가 된다.
또 만약 변경하려는 파라미터의 엔티티의 필드값이 null인 상태라면 해당값이 그 상태로 변경될 것이다.
이를 방지하기위해 직접 save()보단 dirty checking을 이용해 entity의 변경을 확인하고 저장하는게 더 좋다.