나의 GitHub를 보고 내 코드 중 반복문 안에서 save를 쓴 부분에 대해 질문을 주셨다.
프로젝트를 진행하면서 빠르게 기능 구현을 하다보니
별 생각없이 작성한 코드였다.
그래서 정말 부끄러웠다...
하지만 이런게 다 피가되고 살이되겠지 뭐....ㅠ..
그래서 두 메소드를 제대로 비교해보고 차이를 알고 사용하기로 했다.
@Transactional
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Entity must not be null.");
if (this.entityInformation.isNew(entity)) {
this.em.persist(entity);
return entity;
} else {
return this.em.merge(entity);
}
}
@Transactional
public <S extends T> List<S> saveAll(Iterable<S> entities) {
Assert.notNull(entities, "Entities must not be null!");
List<S> result = new ArrayList();
Iterator var3 = entities.iterator();
while(var3.hasNext()) {
S entity = var3.next();
result.add(this.save(entity));
}
return result;
}
우선 두 메소드는 위와 같이 되어있다.
saveall()을 보면 결국 save()를 반복해서 호출하는 형태이다.
얼핏보면 똑같은거 아닌가? 라고 생각했다.
하지만 자세히 들여다보고 생각해보니 중요한 것은 두 메소드에 붙어있는
@Transactional이 붙은 클래스는 프록시로 빈으로 등록된다.
따라서 주입받은 객체를 사용할 경우 프록시가 들어오게 되고 접근 시 프록시 객체를 통한 호출이 이뤄진다.
즉 @Transactional이 붙은 save()를 10번 호출하면 10번 모두 프록시를 통해 접근한다.
하지만 saveall()의 내부에서 save를 호출한것처럼 this.save()와 같이 내부 호출을 하게 되면 프록시를 통한 접근이 아니다.
이 차이로 인해 두 메소드는 성능에서 큰 차이를 보이게 되는 것 같다.
이런 차이를 눈으로 확인하고 바로 코드를 수정했다....
부끄러운 면접이었다..흑....