Natural Id 사용

Kyojun Jin·2024년 6월 25일

Spring

목록 보기
11/12

데이터 정합성을 보장하기 위해서 surrogate key 를 사용하곤 한다.

주로 UUID나 autoincrement integer id 를 사용한다.

surrogate key 는 db의 정합성을 보장하지만 별 정보가 없다는 단점이 있다.

정보에 의미가 없다는 것은 나중에 정보를 찾기도 쉽지가 않고, 디버깅 하기도 어렵다.

그래서 pk는 그걸로 두되, natrual key를 따로 사용할 수 있다.

natural key는 사용자의 아이디나 이메일같이 유니크하게 식별 가능한 키이다.

테이블의 조인 성능, 데이터 추가 시 정합성을 위해 랜덤한(혹은 sequential한) 값을 사용하면서 막상 조회할 때는 사람이 알아볼 수 있는 Natural Key를 사용할 수 있다.

다만 JPA는 1차 캐싱 시 ID만 지원한다. Natural Key에 해당하는 칼럼에 대해 DB 측에서 인덱싱을 할 지라도 일단 쿼리 한 번은 나가고 본다.
따라서 JPA에서 Natural Key와 실제 Id를 매핑하는 작업이 필요하다.

JPA에서 natural id 를 지원한다.

@Entity
class User {
	@Id
    var userId: Int = 0
    
    @NaturalId
    var username: String = ""
}

그리고 Jpa는 이를 자동으로 지원하지 않기 때문에 하이버네이트를 이용해서 매핑해준다.

@NoRepositoryBean
interface BaseRepository<T, ID, NID> : JpaRepository<T, ID> {
    fun findByNaturalKey(nid: NID): Optional<T & Any>
}

class BaseRepositoryImpl<T, ID :Serializable, NID : Serializable>(
    entityInformation: JpaEntityInformation<T, *>,
    private val entityManager: EntityManager,
) : SimpleJpaRepository<T, ID>(entityInformation, entityManager), BaseRepository<T, ID, NID> {
    override fun nnnnn(nid: NID): Optional<T & Any> {
        val entity = entityManager.unwrap(Session::class.java).bySimpleNaturalId(this.domainClass).load(nid)
        return if (entity != null)
            Optional.of(entity)
        else {
            Optional.empty()
        }
    }
}

JPA Config 클래스에서 다른 JpaRepository 구현체가 BaseRepositoryImpl을 상속받을 수 있도록 한다.

@Configuration
@EnableJpaRepositories(
    basePackages = ["com.example"],
    repositoryBaseClass = BaseRepositoryImpl::class
)
class PersistenceConfig {
}

이후 BaseRepository를 상속받은 레포지토리는 findByNaturalKey를 사용하여 natrual id 에 해당하는 칼럼으로 쿼리를 캐싱할 수 있다.

0개의 댓글