[SpringData] Persistable

KMS·2022년 4월 27일
0

SpringData

목록 보기
8/9

지금까지 봐왔던 예시에서는 모든 엔티티들의 PK들이 @GeneratedValue를 사용해서 자동으로 Long 타입으로 부여되도록 했습니다. 하지만, 실무에서는 이런 방식으로만 PK를 부여하기에는 한계가 있습니다. 회원정보의 PK를 Unique하게 하기 위해서 UUID로 설정을 하게 되기만 하더라도 회원정보 엔티티의 PK는 String으로 해줘야 합니다. 이런 경우에 발생하는 성능적인 문제와 해결 방법을 보도록 하겠습니다.

문제가 생기는 이유

@GeneratedValue를 사용해서 DB에서 자동으로 PK값을 순차적으로 부여해줄 경우, JPA에서 바로 persist()를 호출 한 후, DB에 값이 저장된 후에 PK값이 부여됩니다. 그러나, @GeneratedValue를 사용하지 않아서 개발자가 직접 PK값을 부여해주는 경우, PK값이 부여된 상태에서 DB로 값이 넘어가게 됩니다. 이때, PK값이 부여됐기 때문에, JPA는 merge()를 호출합니다. merge()를 호출할 경우, DB에 접근을 해서 동일한 PK 값을 가진 데이터가 있는 지 먼저 확인을 한 후, 데이터가 없을 경우에 새로운 데이터로 인지하고 저장을하게 됩니다. 그렇기 때문에, 데이터를 저장하기 전에 추가로 DB를 접근하기 때문에 비효율 적입니다. 이런 문제를 해결하기 위해서 Persistable을 사용합니다.

엔티티( +BaseEntity)

DataBaseTimeEntity

@EntityListeners(AuditingEntityListener.class)
@Getter
@MappedSuperclass // BaseEntity의 속성들을 상속 받는 엔티티 들이 속성 값들로 가질수 있도록 해줌
public class DataBaseTimeEntity {

    @CreatedDate
    @Column(updatable = false) //해당 값을 한번 생성하면 변할수 없도록 해줌
    protected LocalDateTime createdDate;

    @LastModifiedDate
    protected LocalDateTime lastModifiedDate;

}

Item

@Entity
@Getter
public class Item extends DataBaseTimeEntity implements Persistable<String>{

    @Id
    private String id;

    protected Item() {
    }

    public Item(String id) {
        this.id = id;
    }

    /**
     * Persistable 을 상속 받아서 isNew() 메서드에서 해당 엔티티가 새로운 엔티티인지 아닌지를 판별해 줄 수 있다.
     * 새로운 엔티티이면, createdDate가 NULL이기 때문에, createdDate가 NULL인지 아닌지에 따라서 판별하도록하면 편리합니다.
     */
    @Override
    public boolean isNew() {
        return this.createdDate == null;
    }
}

위에서 살펴본 문제를 해결하기 위해서 엔티티에 Persistable<ID>를 상속받습니다(ID는 PK값의 타입). Persistable은 getId()와 isNew() 메서드를 가지고 있으며, isNew()에서는 저장할려는 엔티티가 DB에 존재하는지 존재하지 않는지 판별해주는 메서드 입니다. 이때, isNew()는 오버라이딩해서 개발자가 직접 로직을 구현해 주면 됩니다.
추천드리는 방법은 createdDate를 확인하는것 입니다. createdDate는 엔티티가 DB에 존재하지 않는 엔티티라면 null 값을 가지고 있습니다. 그렇기 떄문에 null 값을 갖고 있으면 새로운 엔티티라는 것을 알 수 있습니다.

결과:

  • Scenario #1: Item.id -> Long && @Generated Value:
    1.insert into item (id) values (?);
  • Scenario #2: Item.id -> String without Persistable:
    1.select item0.id as id1_0_0 from item item0 where item0.id=?;
    1. insert into item (id) values (?);
  • Scenario #3: Item.id -> String w/ Persistable:
    1. insert into item (id) values (?);
      보다시피, Persistable을 사용하지 않았을때에는 DB에 해당 PK값을 가진 엔티티가 있는 확인을 하는 쿼리문이 추가로 실행됩니다.
profile
Student at Sejong University Department of Software

0개의 댓글