[Spring Data JPA] JPA 엔티티 설계 시 생성자 접근 제한을 PROTECTED로 설정하는 이유

2025. 1. 21. 11:04·BackEnd/Spring & JPA

1. 시작하며

Spring Data JPA를 활용하여 애플리케이션을 개발하다 보면 엔티티(Entity) 설계는 매우 중요한 요소로 다가옵니다. 특히, Entity의 생성자 접근 제한과 같은 세부적인 설계는 시스템의 안정성과 데이터 일관성을 유지하는 데 큰 영향을 미칩니다.

이번 글에서는 회원 엔티티(Entity)를 설계하며 @NoArgsConstructor와 @AllArgsConstructor를 AccessLevel.PROTECTED로 제한한 이유를 다룹니다. 이러한 설계가 가지는 장점과 실제로 어떤 효과를 기대할 수 있는지에 대해 설명합니다.

2. JPA 엔티티 기본 설계

JPA 엔티티는 데이터베이스 테이블과 1:1로 매핑되는 클래스입니다. 아래는 Member 엔티티의 예시입니다.

@Entity
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@Table(indexes = {
    @Index(name = "idx_email", columnList = "email")
})
public class Member extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String email;

    private String password;

    @Column(nullable = false)
    private String nickname;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    private MemberRole role;

    // 연관 관계 설정 생략
}

3. AccessLevel.PROTECTED를 사용하는 이유

Spring Data JPA와 JPA 표준은 엔티티 생성 및 초기화 과정에서 특정 생성자를 요구합니다. 하지만 무분별하게 생성자를 사용하면 데이터의 안정성을 해칠 수 있습니다. 이를 방지하기 위해 @NoArgsConstructor와 @AllArgsConstructor를 PROTECTED로 설정하는 것이 중요합니다.

3.1 @NoArgsConstructor(access = AccessLevel.PROTECTED)

1) JPA 프록시 객체 생성

  • JPA는 내부적으로 프록시 객체를 생성하여 엔티티를 관리합니다.
  • 이 과정에서 기본 생성자가 반드시 필요합니다.
  • 기본 생성자가 없으면 org.hibernate.InstantiationException 에러가 발생합니다.

2) 기본 생성자의 위험성

  • 기본 생성자가 public으로 열려 있으면, 아래와 같이 필수 데이터가 누락된 불완전한 객체를 생성할 수 있습니다.
// 잘못된 사용 예시
Member member = new Member(); // 기본 생성자 호출
  • 위 코드처럼 초기화되지 않은 필드로 엔티티를 생성하면, 데이터 무결성을 해칠 위험이 있습니다.

3) 해결책: AccessLevel.PROTECTED

  • 기본 생성자를 PROTECTED로 설정하여 외부에서 직접 호출하지 못하도록 제한합니다.
  • JPA 내부적으로만 기본 생성자를 호출하게 하여 안전한 엔티티 초기화를 보장합니다.

3.2 @AllArgsConstructor(access = AccessLevel.PROTECTED)

1) 모든 필드 초기화 생성자의 문제점

  • @AllArgsConstructor는 모든 필드를 초기화하는 생성자를 자동으로 생성합니다.
  • 그러나 이 생성자가 public으로 열려 있으면, 외부에서 임의의 값으로 객체를 생성할 수 있습니다.
// 잘못된 사용 예시
Member member = new Member(null, null, null, null, null);
  • 위와 같은 방식은 잘못된 데이터가 생성되고 저장되는 위험을 초래합니다.

2) Builder 패턴과의 연계

  • @AllArgsConstructor를 PROTECTED로 설정하면, Builder 패턴을 통한 객체 생성을 강제할 수 있습니다.
  • Builder 패턴은 필수 값만 설정하고 선택적인 값은 유연하게 처리할 수 있도록 도와줍니다.
Member member = Member.builder()
    .email("example@example.com")
    .nickname("nickname")
    .build();

3) 팩토리 메서드 활용

  • 생성자를 PROTECTED로 제한하면 팩토리 메서드로 엔티티 생성 과정을 제어할 수 있습니다.
public static Member createMember(String email, String password, String nickname) {
    return new Member(email, password, nickname, MemberRole.USER);
}

4. 정리: @NoArgsConstructor와 @AllArgsConstructor를 PROTECTED로 설정해야 하는 이유

@NoArgsConstructor JPA 내부에서만 기본 생성자 호출을 허용하여 불완전한 객체 생성을 방지
@AllArgsConstructor Builder 패턴이나 팩토리 메서드를 통해 객체 생성을 통제하고 데이터 무결성 보장

5. 결론

엔티티는 데이터베이스와 애플리케이션 간의 데이터 교환을 담당하며, 잘못된 설계는 데이터 무결성을 위협할 수 있습니다.

이번 글에서는 @NoArgsConstructor와 @AllArgsConstructor를 AccessLevel.PROTECTED로 설정하여 데이터 무결성을 유지하고 안전한 객체 생성을 보장하는 방법을 살펴보았습니다.

  • 기본 생성자는 JPA 내부에서만 사용되도록 제한하여 불완전한 객체 생성을 방지합니다.
  • 모든 필드 초기화 생성자는 Builder 패턴 또는 팩토리 메서드와 연계하여 안전한 데이터 처리를 가능하게 합니다.

'BackEnd > Spring & JPA' 카테고리의 다른 글

[Spring Boot] MySQL Master/Slave 복제 설정과 Read/Write 자동 분기 처리 방법 정리  (0) 2025.03.24
[Spring] @RequestPart를 활용하여 JSON + MultipartFile 동시 전송하기 (Feat. 게시판에서 게시물 생성과 첨부 파일 업로드 한번에 처리하기)  (0) 2025.02.13
[Spring] @ResponseBody VS ResponseEntity<T>  (0) 2025.01.06
[Spring] @Controller VS @RestController  (0) 2025.01.06
[Spring] 스프링 개념 및 동작 원리 정리  (0) 2025.01.05
'BackEnd/Spring & JPA' 카테고리의 다른 글
  • [Spring Boot] MySQL Master/Slave 복제 설정과 Read/Write 자동 분기 처리 방법 정리
  • [Spring] @RequestPart를 활용하여 JSON + MultipartFile 동시 전송하기 (Feat. 게시판에서 게시물 생성과 첨부 파일 업로드 한번에 처리하기)
  • [Spring] @ResponseBody VS ResponseEntity<T>
  • [Spring] @Controller VS @RestController
개발자 동긔
개발자 동긔
배우고 느낀점들을 기록합니다. 열정 넘치는 백엔드 개발자로 남고싶습니다.
  • 개발자 동긔
    Donker Dev
    개발자 동긔
  • 전체
    오늘
    어제
    • Category (39)
      • BackEnd (23)
        • JAVA (15)
        • Spring & JPA (7)
      • Database (4)
      • Computer Science (2)
        • Network (0)
        • Security (0)
        • Web (1)
      • DevOps (6)
        • Docker (1)
        • Jenkins (0)
        • Monitoring (2)
        • CICD (1)
      • 트러블 슈팅 (3)
      • 성능 개선 (1)
      • Project (0)
  • 인기 글

  • 태그

    java
    restful api 설계
    spring boot
    SSH
    인터페이스
    spring cloud msa
    Database
    @RequestBody
    nginx
    JPA
    master/slave db 이중화 처리
    docker
    Spring
    와일드카드
    Jenkins
    interface
    restful api
    docker compose
    mysql master/slave replication
    CICD
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
개발자 동긔
[Spring Data JPA] JPA 엔티티 설계 시 생성자 접근 제한을 PROTECTED로 설정하는 이유
상단으로

티스토리툴바