DEV/Spring Data JPA

Entity의 Id를 직접 지정할 때 주의사항 (persist vs merge)

행운개발자 2023. 9. 27. 09:55
728x90

시스템이 매우 큰 경우 또는 어떤 이유로든 Entity의 @Id를 직접 지정해야하는 경우가 있습니다.

이럴 때에는 아래와 같이 Persistable의 isNew를 override 해주어야 합니다. isNew 판단 여부는 Audit의 기능을 사용했습니다.

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member extends BaseEntity implements Persistable<Long> {

    @Id
    @Column(name = "member_id")
    private String id;

    @Override
    public boolean isNew() {
        return super.getCreatedDate() == null;
    }
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter
public abstract class BaseEntity {

    @CreatedBy
    private String createdBy;

    @LastModifiedBy
    private String lastModifiedBy;


    // 필요한 경우 BaseTimeEntity로 분리하기
    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createdDate;

    @LastModifiedDate
    @Column(updatable = false)
    private LocalDateTime lastModifiedDate;
}
@EnableJpaAuditing
@SpringBootApplication
public class App {

	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}

	@Bean
	public AuditorAware<String> auditorProvider(){
		// spring security
		return () -> Optional.of(UUID.randomUUID().toString());
	}
}

Persistable의 isNew를 override 해주지 않으면 SimpleJpaRepository의 save를 호출할 때 새로운 객체로 인식되지 않아 merge가 호출됩니다. merge는 수행과정에서 select 쿼리를 한 번 호출하기 때문에 persist보다 비효율적입니다.

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

이러한 방법을 쓰기 전에 정말로 @GeneratedValue(strategy = GenerationType.AUTO)를 사용하지 않아야하는 이유가 있는지는 고민해보아야 합니다.

728x90