Spring Data JPA 트랜잭션에서 save()와 saveall() 비교

CHOI YUN HO·2022년 10월 23일
0
post-custom-banner

최근 어떤 IT기업의 기술면접에서 있었던 일이다.

나의 GitHub를 보고 내 코드 중 반복문 안에서 save를 쓴 부분에 대해 질문을 주셨다.

프로젝트를 진행하면서 빠르게 기능 구현을 하다보니
별 생각없이 작성한 코드였다.
그래서 정말 부끄러웠다...
하지만 이런게 다 피가되고 살이되겠지 뭐....ㅠ..

그래서 두 메소드를 제대로 비교해보고 차이를 알고 사용하기로 했다.

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);
        }
    }

saveall()

@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이 붙은 클래스는 프록시로 빈으로 등록된다.
따라서 주입받은 객체를 사용할 경우 프록시가 들어오게 되고 접근 시 프록시 객체를 통한 호출이 이뤄진다.

즉 @Transactional이 붙은 save()를 10번 호출하면 10번 모두 프록시를 통해 접근한다.

하지만 saveall()의 내부에서 save를 호출한것처럼 this.save()와 같이 내부 호출을 하게 되면 프록시를 통한 접근이 아니다.
이 차이로 인해 두 메소드는 성능에서 큰 차이를 보이게 되는 것 같다.

이런 차이를 눈으로 확인하고 바로 코드를 수정했다....
부끄러운 면접이었다..흑....

profile
가재같은 사람
post-custom-banner

0개의 댓글