ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] Spring Data JPA의 save 함수 구조
    Spring 2022. 6. 17. 21:09

    Spring Data JPA의 save함수의 구조는 다음과 같다.

     

    public <S extends T> S save(S entity) {
    
    	if (entityInformation.isNew(entity)) { // 1
    		em.persist(entity); // 2
    		return entity; // 3
    	} else { // 4
    		return em.merge(entity); // 5
    	}
    }

    1번의 isNew 함수를 통해 매개변수로 들어온 entity가 새로운 entity인지, 이미 저장된 entity인지 체크한다.

      - 레퍼런스 타입(String, Long...)일 경우 null값이면 새로운 entity로 판단한다.

      - 기본 타입(Primitive Type)[int, long, char etc..]일 경우 값이 0이면 새로운 entity로 판단한다.

     

    따라서 id 생성 방식이 @GeneratedValue이라면 엔티티가 저장되기 전에는 id값이 null이거나 0이기 때문에 2번, 3번을 차례로 진행한다.

    2번과정을 진행한 entity의 id값에는 @GeneragedValue 속성에 맞게 값이 채워져 있다.

     

    그렇다면 id값이 @GeneratedValue방식이 아니라 사용자가 직접 입력하는 값이라면 어떤식으로 판별할까

     

    우선 아무런 설정이 되있지 않다면, id값에는 보통 값이 채워져 있을 것이기 때문에, 1번구간을 넘어가지 못하고 4번으로 넘어가 merge를 하게 된다.

    merge을 하게 될 경우 해당 entity가 데이터베이스에 존재하는지 체크하기 위해 select 쿼리가 한번 발생하게 된다.

    insert가 발생하기 전 select가 한번 발생하는 것을 볼 수 있다.

     

    이렇게 @GeneratedValue을 쓰지 않은 채로 별다른 설정이 없으면 매 저장시마다 Select 쿼리가 한번씩 발생할 수 밖에 없다.

    이를 위해 다음과 같이 문제를 해결할 수 있다.

     

    @Entity
    @Getter
    @EntityListeners(AuditingEntityListener.class)
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    public class Movie implements Persistable<Long> {
    
        @Id
        @Column(name="movie_id")
        private Long id;
    
        private String title;
        private String thumbnail;
        private String directorName;
        private Integer year;
        private String naverUrl;
        private String nation;
        private Double popularity;
        private String actors;
    
        @CreatedDate
        @Column(updatable = false)
        private LocalDateTime createdDate;
    
        private LocalDateTime lastModifiedDate;
    
        @Override
        public boolean isNew() {
            return getCreatedDate() == null;
        }
    }

    해당 entity에 Persistable<id타입>을 상속받아 isNew을 커스텀할 수 있는 방법이 있다.

    이를 이용해 createDate이나 다른 기타 판별방식을 활용해 select 쿼리를 안나갈 수 있도록 할 수 있다.

    댓글

Designed by Tistory.