본문 바로가기
카테고리 없음

JPA entity에서 Id 값은 왜 -1이 아닌 0으로 지정할까?

728x90

 

 

반응형

 

 


 JPA에서 기본 ID 값은 왜 0으로 지정할까?

 

Spring JPA를 사용하면서 보통은 DB의 Id 전략을 따른다. (주로 auto increasement)

 

Long 타입을 Id 값으로 사용 시 왜 기본값으로 0을 설정할까? 아직 값이 지정되지 않았다는 의미로 -1을 사용하면 안 될까?

 

관성적으로 0을 사용해 왔는데 문득 의문이 들어 코드를 살펴보았다. 

 

 

 


 내부 구현

 

spring JPA에서 우리가 사용하는 repository들은 JpaRepository 인터페이스를 구현한다. 이때 실 구현체는 SimpleJpaRepository이다.

public class SimpleJpaRepository{
	...
    
    @Transactional
    public <S extends T> S save(S entity) {
        Assert.notNull(entity, "Entity must not be null");
        if (this.entityInformation.isNew(entity)) {
            this.entityManager.persist(entity);
            return entity;
        } else {
            return (S)this.entityManager.merge(entity);
        }
    } 
    
    ...
}

 

repository.save시 entity의 new 여부에 따라 persist 혹은 merge로 나뉘는 것을 볼 수 있다. 

 

persist는 신규 영속 상태를 만들고 바로 INSERT를 실행. 해당 id가 존재한다면 예외가 발생한다.

 

merge는 해당 entity를 다시 영속 상태로 만들기 때문에 DB에 값이 있다면 UPDATE, 없을 경우 INSERT가 발생한다. 

 

즉 merge가 발생한다면 2번의 쿼리가 발생하는 것이다.(있는지 조회 + 없다면 업데이트)

 

 

 


Entity new 여부 판단

 

그렇다면 전달된 entity의 new 여부는 어떻게 판단할까?

public abstract class AbstractEntityInformation{
	...
    public boolean isNew(T entity) {
        ID id = (ID)this.getId(entity);
        Class<ID> idType = this.getIdType();
        if (!idType.isPrimitive()) {
            return id == null;
        } else if (id instanceof Number) {
            Number n = (Number)id;
            return n.longValue() == 0L;
        } else {
            throw new IllegalArgumentException(String.format("Unsupported primitive id type %s", idType));
        }
    }
    ...
}

 

코드 내부를 살펴보면 id값에 따라 다르게 처리한다.

 

기본 자료형이 아닐 때는 null일 때 new로 판단하고, Number 타입일 때는 0일 때만 new로 판단하고 있다. 

 

만약 entity의 id 값을 -1로 지정한다면 여기에서 new로 판단하지 않기 때문에 mege를 하게 되고, id=-1인 entity가 있는지 SELECT 후 없으므로 신규 INSERT를 하게 되는 구조이다.

 

실제로 디버깅 로그를 보아도 id=0인 entity는 바로 INSERT 쿼리를 날리지만, id=-1인 entity는 UPDATE와 INSERT 쿼리가 각각 발생하게 된다.

728x90
반응형