모든 엔티티에는 primary key(주키)가 있다.
나는 지금까지 java로 개발할때 primary key를 @GeneratedValue(strategy = GenerationType.IDENTITY)을 활용해 Long을 사용했다. int보다 많은 양의 수를 처리하고 자동으로 값을 늘려주는 장점이 있기에? 편리해서? 그냥 딴 사람이 다 이렇게 써서? 이런 이유였다.
kotlin을 공부하던 중 Long 형을 한계에 대해 보았다.
1. 다른 entity끼리의 키값으로 중복이 될 수 있음(유일성)
2. 그래도 Long 형이 가진 범위가 적을 수 있다??-> 가능성은 적겠지만
이런 이 부분을 uuid 타입은 해결해준다고 한다.
UUID(Universally Unique Identifier)는 정보 시스템에서 객체나 엔티티를 고유하게 식별하기 위해 사용되는 128비트 길이의 식별자이다.
Long 타입의 2배이니 2번 조건을 해결해주고
실제로 테스트해보니 0191bbaa-74cd-75d9-aba7-dada993c5d5b 이런 형태의 값이 나온다. 겹칠일도 없으니 1번도 해결이다.
하지만 단점이 있다.
Long타입의 경우 순서를 가질 수 있기 때문에 정렬 시 성능적인 이점이 있었지만, uuid는 순서가 없다.
그래서 또 발전된? 게 뭐냐 하면 ulid이다.
데이터 크기도 UUID에 비해 작기 때문에 저장용량 및 생성 비용을 적게 가져갈 수 있다는 장점이 있다고 한다.
또한 시간순으로 정렬이 가능하다는 점에서 정렬적인 단점도 해결이 된다.
그런데 라이브러리를 가져와서 사용해야하기에 FasterXML에서 제공하는 java-uuid-generator (JUG) 라이브러리를 사용하여 kotlin entity를 만들어봤다.
UserEntity를 정의하고 주키를 String으로 준 후 DomainId를 dataClass로 정의하고 User 객체를 만들때 uuid 타입의 주키를 생성하고 String으로 변환 이런 형식이다.
이렇게 한 이유는 다음과 같다.
지금 나는 간단한 프로젝트를 하고 있기에 이런 방식을 채탁했다!
나중엔 ULID로 디벨롭 해볼 예정이다.
import com.fasterxml.uuid.Generators
data class DomainId(
val id: String
) {
companion object{
fun generate(): DomainId {
return DomainId(Generators.timeBasedEpochGenerator().generate().toString())
}
}
}
package com.ddaom.back.domain.user.model
import com.ddaom.back.domain.common.DomainId
data class User (
val id: String = DomainId.generate().id,
val nickname: String,
var gender: String,
val age: Int,
val thumbnail: String,
val refreshToken: String = ""
){
}
import com.ddaom.back.domain.novel.model.Novel
import com.ddaom.back.domain.user.enums.Gender
import com.ddaom.back.domain.user.model.User
import com.ddaom.back.infra.persistence.novel.entity.NovelEntity
import jakarta.persistence.*
@Entity
@Table(name = "user")
class UserEntity (
@Id
@Column(name = "id", unique = true)
val domainId: String,
@Column(name = "nickname")
val nickname: String,
@Column(name = "gender")
@Enumerated(EnumType.STRING)
val gender: Gender,
@Column(name = "age")
val age: Int,
@Column(name = "thumbnail")
val thumbnail: String,
@Column(name = "refreshToken", length = 1000)
val refreshToken: String
){
companion object {
fun of(user: User) =
UserEntity(
domainId = user.id,
nickname = user.nickname,
gender = Gender.getEnumGender(user.gender),
age = user.age,
thumbnail = user.thumbnail,
refreshToken = user.refreshToken
)
fun fromId(userId: String) =
UserEntity(
domainId = userId,
nickname = "",
gender = Gender.OTHER,
age = 0,
thumbnail = "",
refreshToken = ""
)
}
fun updateRefreshToken(newRefreshToken: String): UserEntity {
return UserEntity(
domainId = this.domainId,
nickname = this.nickname,
gender = this.gender,
age = this.age,
thumbnail = this.thumbnail,
refreshToken = newRefreshToken
)
}
}
fun UserEntity.toDomain() = User(
id = this.domainId,
nickname = this.nickname,
gender = this.gender.stringGender,
age = this.age,
thumbnail = this.thumbnail,
refreshToken= this.refreshToken
)