[Spring] JPA save() vs saveAndFlush()

박성우·2023년 5월 18일
0

Spring

목록 보기
3/10

우선, save와 saveAndFlush의 차이 및 동작 원리를 알려면 우선 save 메소드와 saveAndFlush 메소드가 무엇이고 어떤 역할을 하는지부터 알아야한다.

일반적으로 우리는 save 메소드를 호출할 때 JpaRepository 인터페이스를 상속받은 우리만의 Repository 인터페이스로부터 호출한다.

그 이유는 save 메소드를 구현한 SimpleJpaRepository을 상속받은 구현체를 주입받기 때문인데, 자세한 내용은 해당 포스트에 작성해둔 적이 있다.

다음은 SimpleJpaRepository 클래스 내부에 구현되어 있는 save 메소드와 saveAndFlush 메소드이다.


save(S)

save 메소드를 간단하게 살펴보자면, 새로운 식별자를 가진 Entity의 경우 EntityManager의 persist 메소드를 호출하여 영속성 컨텍스트에 저장하고, 준영속 상태의 Entity, 즉 영속성 컨텍스트에 저장된 적이 있지만 현재는 저장되어 있지 않은 Entity를 영속성 컨텍스트에 저장한다.

결과적으로 save 메소드의 기능은 Entity를 영속성 컨텍스트(1차 캐시)에 저장하는 것이다.

하지만, 영속성 컨텍스트에 저장하는 것이지, 데이터베이스에 저장하는 것이 아님에도 불구하고 save 메소드를 실행하면 데이터베이스에 값이 저장되어있다.

그 이유는 save 메소드에 적용되어있는 @Transactional 어노테이션 때문이다. Transaction 단위로 메소드가 실행되고 나면 마지막에는 commit을 하기 때문에 결과적으로 영속성 컨텍스트에 저장되어있는 것들이 데이터베이스에 반영되게 된다.

따라서, save 메소드를 사용하면 JPA의 SQL 쓰기 지연 저장소에 쿼리가 저장되어 있다가 트랜잭션이 커밋될 때 flush()가 호출되고 데이터베이스에 쿼리가 보내져서 값이 저장되는 것이다.

여기서 한 가지 더 주의할 점이 있는데,

❓다음과 같이 save 메소드를 호출한 다음 EntityManager의 clear 메소드를 호출해서 영속성 컨텍스트를 비우게되면, DB에 course가 저장이될까?

save 메소드가 끝날 때 트랜잭션의 커밋이 일어나서 저장이 될 것 같지만, 트랜잭션에는 전파(Propagation) 옵션이 있어서 기본값인 REQUIRED에 의해서 부모 메소드인 createCourse 에 트랜잭션이 존재하면 자식 메소드 save 메소드의 트랜잭션이 부모 트랜잭션에 합류하게 된다..!!

따라서 부모 트랜잭션이 끝나기 전까지는 commit이 일어나지 않아서 결국 course는 데이터베이스에 저장되기 전에 영속성 컨텍스트로부터 지워지는 것이다.

saveAndFlush(S)

saveAndFlush 메소드는 save 메소드를 호출하고 flush 메소드가 호출되므로 save 메소드에 의해 SQL 저장소에 쿼리가 저장되어 있다가 트랜잭션 커밋을 기다리지 않고 바로 flush()를 통해 쿼리를 DB에 반영시킨다.

따라서, 당연하게도 saveAndFlush 메소드 후에는 clear()를 호출해도 이미 DB에 반영이 된 이후여서 데이터는 저장되어있을 것이다.


세 줄 요약하자면,
1. save 메소드는 영속성 컨텍스트에 값을 저장해두었다가 트랜잭션이 커밋될 때 데이터베이스에 반영된다.
2. saveAndFlush 메소드는 영속성 컨텍스트에 저장한 다음 바로 영속성 컨텍스트로부터 데이터베이스에 반영되게 한다.
3. save 메소드는 트랜잭션 단위와 연관되어 저장이 되는 것이기 때문에 트랜잭션 전파에 따라 상황이 달라질 수 있다.

profile
Backend Developer

0개의 댓글