쌩로그

JPA로 Entity ID에 UUID 타입 사용하기(with. MySQL 8.x) 본문

Spring/JPA

JPA로 Entity ID에 UUID 타입 사용하기(with. MySQL 8.x)

.쌩수. 2024. 1. 24. 23:31
반응형

목록

  1. 포스팅 개요
  2. 본론
      2-1. UUID가 왜 필요한가?
      2-2. UUID가 뭔데?
      2-3. 코드로 살펴보기
  3. 요약

1. 포스팅 개요

해당 포스팅은 JPA 를 사용하면서 Entity 의 Id 값으로, Auto Increment가 아닌, 랜덤 문자열을 가지는 UUID로 사용하는 내용에 대한 포스팅이다.

2. 본론

2-1. UUID가 왜 필요한가?

늘 JPA를 어떤 CRUD 연습용이던가, 혹은 프로젝트를 할 때 로컬환경에서도, 배포환경에서도 MySQL의 기본 키 전략에는 Auto Increment를 적용하여, 알아서 id값이 할당받도록 하였다.

그런데 이번에 회사에서 프로젝트를 하면서 id를 Auto Increment 로만 의존하기에는 한계가 생길 것 같아 Id 깂으로 UUID의 값을 집어넣으려 한다.

예를 들면, 오키와 같은 게시판이 있다고 가정하고, 프로젝트 모집 게시판, 커뮤니티 게시판, 회사 게시판 등등이 있다고 가정했을 때,

프로젝트 모집, 커뮤니티, 회사 3 도메인의 게시글을 등록할 때마다 첨부파일을 넣을 수 있다고 가정한다.

처음엔 각 도메인과 첨부파일이 일대다 관계이므로, 각 도메인마다 따로 테이블을 만들어주려고 했었다.

그러나, 불필요한 테이블 낭비라고 생각되었고, 각 테이블이 (이미 느끼신 분도 있겠지만) 중복의 느낌이 너무나 강하다.

그래서 첨부파일에 대한 테이블을 하나로 묶어야겠다고 생각되었는데, "각 도메인의 데이터에 대한 첨부파일을 하나의 테이블에 저장하려니 어떻게 하지?"라는 생각을 하다가 MySQL에서 제공하는 좋은 기능인 Auto Increment로는 한계가 있다고 생각하였고, 어떤 도메인이든 고유값을 줄 수 있는 UUID값으로 id를 주어야겠다고 생각하였다.

그래서 UUID를 ID에 Setting하는 코드와 MySQL의 결과를 보여주려고 한다.

2-2. UUID가 뭔데?

개념상은 네트워크 상에서 고유성이 보장되는 id를 만들기 위한 표준 규약이고, Universally Unique IDentifier의 약어로서 범용 고유 식별자라고 한다.

그냥 유일성이 보장되게 하기 위해 탄생한 고유식별자이다.
즉, 겹칠 일이 없다.

이 글을 참고하면 충분할 거 같다.

2-3. 코드로 살펴보기

이제 코드로 살펴보자.
그냥 정말 간단히 하기 위해 다음과 같이 패키지를 구성했다.

그냥 아무 생각없이 나라에 대한 내용이고, 나라 이름과 나라 수도를 저장하는 Entity라고 보면 된다.

Entity이다.

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.UUID;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Country {

    @Id
    @Column(columnDefinition = "BINARY(16)")
    private UUID countryId;

    @Column(name = "name")
    private String name;

    @Column(name = "sudo")
    private String sudoName;

    @Builder
    private Country(UUID countryId, String name, String sudoName) {
        this.countryId = countryId;
        this.name = name;
        this.sudoName = sudoName;
    }


}

Repository이다.

import org.springframework.data.jpa.repository.JpaRepository;

public interface CountryRepository extends JpaRepository<Country, String> {


}

참고로 포스팅해야되지만, 할게 허벌나게 미친듯이 많아서 못하고 있는데,
현재와 같은 interface로 선언된 스프링 데이터 Jpa의 Repository @Repository를 안 붙여도 알아서 스프링이 구현해준다.
(단 JpaRepository를 상속해야한다.)

물론 더 @Repository 애너테이션이 해주는 기능이 있을터지만, 일단 안 붙여도 상관없기 때문에 선언하지 않은 점을 참고하면 될 거 같다.

갑자기 든 생각이지만, 붙여주는 게 명시적이어서 더 좋은 거 같다.. 앞으로 그냥 냅다 붙여야지..

다음은 컨트롤러인데,
그냥 컨트롤러에서 GetMapping치는데, save되게 했다.

import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@RequiredArgsConstructor
public class CountryController {

    private final CountryRepository countryRepository;

    @GetMapping("/temp/country")
    public ResponseEntity tempCountry() {
        Country country = Country.builder()
                .countryId(UUID.randomUUID())
                .name("한국")
                .sudoName("서울")
                .build();
        Country savedCountry = countryRepository.save(country);

        return new ResponseEntity(savedCountry, HttpStatus.CREATED);

    }

}

실행결과를 보면 다음과 같다.

console에 찍힌 로그는 다음과 같다.

다음은 PostMan이다.

PostMan 한번 더!

ID가 바껴있다.

MySQL에서는 어떨까?

흠...

워크벤치에서는 이렇게 나오지만,,,

커맨드에서는 다음과 같이 출력된다.

현재는 원래 UUID가 146 바이트를 잡아먹는데, 16진수로 저장되면서, 146바이트를 잡어먹던 UUID가 16바이트를 먹도록 용량이 줄어들었다.

이에 해당하는 내용은 이글 에서 참고할 수 있다.

3. 요약

이처럼 Auto Increment 전략에서 벗어나 UUID값을 Entity의 기본 키로 사용하게 된 배경과 어떤 식으로 사용할지에 대한 내용을 알아보았다.

728x90
Comments