[TroubleShooting/JPA] save() 사용시 select 가 선행 되는 문제

반응형

문제

특정 데이터를 관리할 때. 두 가지 방식으로 PK 를 관리한다.

 

1. auto increase 되는 숫자를 PK 로 사용한다.

2. loginId, 주민번호, 식별 코드 등등 중복되지 않는 유일한 값을 PK 로 사용한다.

 

두 번째 방식으로 save() 로 새롭게 데이터를 저장할 경우 실행되는 쿼리는 insert 만 실행되길 기대하지만, 데이터를 조회하는 select 가 저장 할 때마다 계속 실행되는 문제가 생겼다.

해결

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

save() 는 특정 값을 통해 분기처리하고, 업데이트와 저장 두 가지의 역할을 수행한다.  ID 가 있는 경우에는 업데이트, 없는 경우에는 저장을 수행하는데. 위의 두 번째 방식으로 진행할 경우 ID 를 직접 부여한 상태로 save() 를 실행하기 때문에 ID 가 존재하기 때문에 업데이트 수행하고, 업데이트 할 데이터를 조회한다. insert 만 실행되길 원한다면 분기처리하는 특정값을 오버라이딩 해주면 된다.

1. isNew() 함수 오버라이딩

- Persistable 인터페이스를 문제의 엔티티에 구현하고, isNew() 함수를 오버라이딩 하면 된다. isNew() 함수의 결과에 따라서 업데이트 할지 저장할지 선택하기 때문에 원하는대로 저장만 수행하기 위해서 결과가 true 인 값을 리턴하도록 하면 된다. 

public class Entity implements Persistable<Long>{

    @Id
    private Long id;

    @CreatedDate
    @Column(name = "create_date", nullable = false)
    private LocalDateTime createDate;


    @Override
    public Long getId() {
        return id;
    }
    @Override
    public boolean isNew() {
        return createDate==null;
    }
}

 

 

해결 방법으로 제시한 위의 코드는 일반적으로 엔티티에 생성 날짜나, 업데이트 날짜 등을 필드로 많이 사용한다. 그리고 해당 값들을 JPA auditing 기능이 persist 단계에서 자동으로 값을 넣어준다. 저 값을 isNew() 함수의 결과에 조건에 넣는다면 저 값은 persist 되기 전까진 항상 null 이기 때문에 새로운 객체로 분기를 타게되고, insert 만 수행되는 원하는 결과를 얻을 수 있다. 

 

 

 

반응형