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의 동작 방식

  1. merge를 실행한다.
  2. 파라미터의 entity의 식별자 값으로 1차 캐시에서 entity를 조회한다.
  3. 만약 없다면 db에서 조회해 저장한다.
  4. 파라미터의 값으로 모든 값을 변경한 후 저장한다.
  5. 커밋되면 해당 변경점을 확인하고 update를 db에 반영한다.

언제 사용하면 좋을까?

save() 경우 새로운 entity를 저장할때 사용하면 좋다.
하지만 새로운 entity가 아닌경우 merge를 사용하게 되는데 merge의 동작방식에서 알 수 있듯이 준영속, 비영속 상태의 엔티티에서 merge는 selet를 이용해 한번 조회한 후 동작하기에 쿼리가 추가적으로 나가 낭비가 된다.
또 만약 변경하려는 파라미터의 엔티티의 필드값이 null인 상태라면 해당값이 그 상태로 변경될 것이다. 이를 방지하기위해 직접 save()보단 dirty checking을 이용해 entity의 변경을 확인하고 저장하는게 더 좋다.