Skip to main content

Command Palette

Search for a command to run...

차근차근 Modern Spring Boot 3 기초 (4) Persistent Entity 만들기(JPA Entity)

Spring Data JPA 사용을 위한 간단한 Entity 만들기

Updated
차근차근 Modern Spring Boot 3 기초 (4) Persistent Entity 만들기(JPA Entity)

Entity, DTO 용어의 제한

Entity는 범용적인 용어입니다. DTO 또한 데이터 전달에 사용되면 모두 DTO라고 할 수 있죠. 하지만 이렇게 넓은 의미로 사용되면, 작업 스타일을 정할 때 방해가 될 수 있습니다.

우리는 다음처럼 entity와 DTO의 의미를 제한해 보겠습니다.

  • Entity: 구체적으로 JPA Entity를 뜻하는 것으로 하겠습니다. 이렇게 하면 결국 테이블에 그대로 대응하는 데이터가 됩니다.

  • DTO: 오직 사용자(또는 다른 서버 등)와 주고 받는, 즉 외부와 교류하는 데이터 양식을 DTO라고 부르겠습니다.

JPA Entity 만들기

우리는 Flyway를 통해 DDL을 실행합니다. 테이블은 그렇게 만들죠.

바꿔서 말하자면, 테이블에 대응하는 JPA Entity도 DDL에 대응하게 만들면 됩니다.

Enum을 통한 상태 목록 관리

Enum은 C언어 시절에도 선택지 목록을 관리할 때 유용한 구조였습니다. 자바에서도 enum 클래스가 선택지 구조에서 유용하게 활용되며, 예를 들어 무언가의 상태(status)를 몇 가지 중 한 가지로 표현할 때 사용할 수 있습니다.

단, enum으로 관리하는 경우, 나중에 목록을 수정할 때마다 프로그램을 다시 배포해야 합니다. 간단히 구분해 보자면 다음과 같습니다. (절대적인 것은 아니며, 항상 상황에 따라 다를 수 있습니다.)

  • 수정할 필요가 (거의) 없는 선택지 목록 관리: enum으로 관리 (재배포에 의존)

  • 수정할 경우가 때때로 생기는 선택지 목록 관리: 데이터베이스를 통해 동적으로 관리.

개발자가 설계할 적에, 예상되는 수정의 빈도만으로 결정했을 때에는 운영 과정에서 생각보다 동적으로 관리해야 했던 것들을 enum으로 작성하였던 경우가 생길 수 있습니다. 따라서 단지 주관적으로 생각한 빈도로 선택하는 것은 아닙니다.

Enum Account Status

우리는 앞서 DDL 작성 시 status라고 하는 컬럼을 작성하였습니다. 타입은 문자열이었습니다. 이것을 enum으로 관리해 보겠습니다. 다음처럼 작성하면 이제 자바 타입으로 사용할 수 있습니다.

  • Package: com.example.demo.auth.domain
public enum AccountStatus {
    /** 가입 대기 */
    PENDING,
    /** 활성화 */
    ACTIVE,
    /** 보호됨(비밀번호를 연속으로 틀리는 등) */
    PROTECTED,
    /** 블락 처리 */
    SUSPENDED,
    /** 휴면 계정 */
    SLEPT,
    /** 삭제된 계정 */
    REMOVED
}

Account Entity 클래스 작성

엔티티 클래스는 우리가 데이터베이스의 테이블을 다룰 때 편리하게 다룰 수 있도록, 테이블에 매핑되는 클래스를 선언한 것입니다. 엔티티는 범용적인 표현이기 때문에, 데이터베이스와 무관한 엔티티 개념도 사용되지만, 우리는 분명히 데이터베이스 테이블을 다루기 위한 JPA 엔티티를 언급하고 있습니다.

엔티티 클래스를 작성하기 위해서는, 앞서 만든 DDL 파일을 보면서 테이블의 컬럼을 알맞게 옮겨 주면 됩니다. 우리는 Flyway를 통해 DDL 관리를 하고 있기 때문에 @Column 같은 애노테이션을 세세하게 작성하지 않아도 됩니다.

DDL Auto의 속성 값을 none으로 했거나 따로 설정하지 않았다면 아무 문제가 없으며, validate 등 세세한 체크를 켜 두었다면 Flyway에 적용된 제약조건을 엔티티에도 반영해야 합니다.

import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.Instant;
import java.util.UUID;
import java.util.function.Supplier;

@Entity
@Table(
        name = "account"
)
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Account {
    @Id
    @GeneratedValue(generator = "uuid2")
    private UUID id;

    private String username;
    private String password;
    private String nickname;
    @Enumerated(EnumType.STRING)
    private AccountStatus status;
    private Instant createdAt;
    private Instant updatedAt;

    // setter 삼가기.
    // 수정할 부분만 모아서 여러 update 메서드를 따로 만드는 것.
}
  • id는 자동으로 생성됩니다.

  • 중요한 것은 우리는 enum 타입을 사용할 때, 가급적 EnumType.String으로 사용합니다. 작성 시 많이 누락하는 부분이니, 잘 체크해 두세요.

  • 또 타임존, 타임 오프셋 등에 구애받지 않는 시스템을 구성하는 것이 좋습니다.

    • GMT, UTC 기준으로 +00:00에 맞추어 타임스탬프를 사용합니다. (유닉스 타임스탬프)

    • 타임존과 그 존의 오프셋은 '클라이언트'가 결정할 영역입니다.

이러한 이유로 시간에는 Instant 타입(Java 8 이상)을 사용하고, DB에서는 timestamp를 사용하는 것이 일반적인 선택이 되고 있습니다. 여러분이 아는 글로벌 테크기업들 중에도 그런 경우가 많죠!

그 외에도 getter는 허용하면서 setter는 잘 허용하지 않는 것이, 널리 쓰이고 있는 기초 아키텍처에서 함께 선택되는 전략입니다. 이는 엔티티 객체의 변화를 방지하기 위한 조치입니다. (일부 아키텍처에서는 변화를 public으로 허용할 수도 있습니다. 몇몇 리스크를 제거한 상태에서 택할 수 있는 전략입니다.)

그리고 위 엔티티 클래스에는 편의상 @Builder를 추가해 두었습니다. 자바는 모던한 언어들에 비해서 생성자나 메서드의 파라미터를 다루는 것이 조금 불편한데, 롬복(lombok)의 빌더는 빌더 패턴을 통해 이를 보완하고 있습니다.


< Prev

Flyway를 통한 DDL 관리

Next >

JPA Entity를 사용하는 JPA Repository

More from this blog

클래스에 Serializable 인터페이스를 구현 받는 이유가 무엇인가요? #42

이 아티클은 깃허브 nettee-space 조직의 디스커션 #42 항목을 옮겨 온 것입니다.관련 논의: nettee-space/backend-sample-hexagonal-simple-crud/discussions/42 Question: 클래스에 Serializable 인터페이스를 구현 받는 이유가 무엇인가요? 여러 소스들을 접하면서 VO 객체 등에 Serializable를 구현받는 것을 많이 접했습니다. 저희 헥사고날(스터디 팀내 2단계 ...

Feb 7, 2025
클래스에 Serializable 인터페이스를 구현 받는 이유가 무엇인가요? #42

개념 2. JWT 액세스 토큰의 생성과 전달, Stateful한 리프레시 토큰의 생성, 전달, 보존

이전 글에서 정리에 꽤 힘을 뺐기 때문에, 이번 글에서는 서두와 부연설명을 줄이고 필요한 정보를 담아 전달해 보겠습니다. JWT 액세스 토큰 JWT 액세스 토큰은 인가에 직접 사용되는 토큰이고, stateless 하다는 장점이 있었습니다. 액세스 토큰의 생성 JWT(JSON Web Token)로 생성합니다. 비밀번호 인증 등 자격 검토 후 JWT를 발급합니다. JWT는 헤더, 페이로드, 시그니처 세 영역을 점(.) 기호로 구분한다고 했습니다....

Oct 23, 2024
개념 2. JWT 액세스 토큰의 생성과 전달, Stateful한 리프레시 토큰의 생성, 전달, 보존

Merge Simpson의 매너 있고 다정한 한국어 개발자 블로그

37 posts