본문 바로가기

JAVA

JPA 엔티티 어노테이션 완전 정리 가이드

반응형

JPA 엔티티 어노테이션 완전 정리 가이드

목차

  1. Lombok 어노테이션
  2. JPA 기본 어노테이션
  3. 관계 매핑 어노테이션
  4. Hibernate 특화 어노테이션
  5. 생명주기 어노테이션

1. Lombok 어노테이션

1.1 @Getter

  • 설명: 필드에 대한 getter 메서드 자동 생성
  • 사용 예시:
    @Getter 
    private String name;
  • 장점: 보일러플레이트 코드 제거, 가독성 향상
  • 단점: 디버깅 시 메서드가 보이지 않음
  • 사용 빈도: 매우 높음 (5/5)

1.2 @Setter

  • 설명: 필드에 대한 setter 메서드 자동 생성
  • 사용 예시:
    @Setter 
    private String name;
  • 장점: 보일러플레이트 코드 제거
  • 단점: 불변성 보장 어려움
  • 사용 빈도: 높음 (4/5)

1.3 @NoArgsConstructor

  • 설명: 파라미터 없는 기본 생성자 생성
  • 사용 예시:
    @NoArgsConstructor 
    public class User {}
  • 장점: JPA 필수 생성자 제공
  • 단점: 불변 객체 생성 시 주의 필요
  • 사용 빈도: 매우 높음 (5/5)

1.4 @AllArgsConstructor

  • 설명: 모든 필드를 파라미터로 받는 생성자 생성
  • 사용 예시:
    @AllArgsConstructor 
    public class User {}
  • 장점: 편리한 객체 생성
  • 단점: 필드 순서 변경 시 문제 발생 가능
  • 사용 빈도: 보통 (3/5)

1.5 @Builder

  • 설명: 빌더 패턴 자동 생성
  • 사용 예시:
    @Builder 
    public class User {}
    

// 사용
User user = User.builder()
.name("홍길동")
.age(30)
.build();

- **장점**: 가독성 좋은 객체 생성, 선택적 필드 설정 용이
- **단점**: @AllArgsConstructor 필요, 기본값 설정 시 @Builder.Default 필요
- **사용 빈도**: 매우 높음 (5/5)

### 1.6 @Builder.Default
- **설명**: Builder 사용 시 필드 기본값 설정
- **사용 예시**: 
```java
@Builder.Default 
private String status = "ACTIVE";
  • 장점: Builder 패턴에서 기본값 유지
  • 단점: @Builder와 함께 사용해야 함
  • 사용 빈도: 높음 (4/5)

1.7 @EqualsAndHashCode

  • 설명: equals()와 hashCode() 메서드 자동 생성
  • 사용 예시:
    @EqualsAndHashCode(of = "seqNo")
  • 장점: 객체 비교 로직 자동 생성
  • 단점: 순환 참조 주의, of 옵션으로 특정 필드만 지정 권장
  • 사용 빈도: 보통 (3/5)

1.8 @ToString

  • 설명: toString() 메서드 자동 생성
  • 사용 예시:
    @ToString(exclude = "password")
  • 장점: 디버깅 용이
  • 단점: 순환 참조 주의, 민감 정보 제외 필요
  • 사용 빈도: 낮음 (2/5)

1.9 @Data

  • 설명: @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor 통합
  • 사용 예시:
    @Data 
    public class User {}
  • 장점: 여러 어노테이션 한 번에 적용
  • 단점: 불필요한 setter 생성 가능, 엔티티에서는 비권장
  • 사용 빈도: 낮음 (2/5)

2. JPA 기본 어노테이션

2.1 @Entity

  • 설명: JPA 엔티티임을 선언, 영속성 관리 대상
  • 사용 예시:
    @Entity 
    public class TbRental {}
  • 장점: JPA가 자동으로 테이블 매핑
  • 단점: 기본 생성자 필수
  • 사용 빈도: 매우 높음 (5/5)

2.2 @Table

  • 설명: 테이블 이름 및 스키마 지정
  • 사용 예시:
    @Table(name = "tb_rental")
    @Table(name = "users", schema = "public")
  • 장점: DB 테이블명과 클래스명 다를 때 유용
  • 단점: 생략 시 클래스명으로 테이블 생성
  • 사용 빈도: 매우 높음 (5/5)

2.3 @Id

  • 설명: 기본키(Primary Key) 지정
  • 사용 예시:
    @Id 
    private Long seqNo;
  • 장점: 엔티티 식별자 명시
  • 단점: 필수 어노테이션
  • 사용 빈도: 매우 높음 (5/5)

2.4 @GeneratedValue

  • 설명: 기본키 자동 생성 전략 지정
  • 사용 예시:
    @GeneratedValue(strategy = GenerationType.IDENTITY)
  • 장점: 자동 증가, UUID 등 다양한 전략 지원
  • 단점: 전략에 따라 성능 차이
  • 사용 빈도: 매우 높음 (5/5)

전략 종류:

  • IDENTITY: DB의 AUTO_INCREMENT 사용 (MySQL, PostgreSQL)
    • 장점: DB에 위임, 간단함
    • 단점: INSERT 후 ID 조회 필요 (성능 이슈)
  • SEQUENCE: DB 시퀀스 사용 (Oracle, PostgreSQL)
    • 장점: 성능 좋음, 배치 처리 가능
    • 단점: 시퀀스 객체 필요
  • TABLE: 별도 테이블로 ID 관리
    • 장점: DB 독립적
    • 단점: 성능 저하, 거의 사용 안 함
  • AUTO: JPA가 DB에 맞게 자동 선택
    • 장점: DB 독립적
    • 단점: 예측 불가능, 비권장

2.5 @Column

  • 설명: 컬럼 매핑 및 속성 지정
  • 사용 예시:
    @Column(name = "rental_name", nullable = false, length = 255)
    @Column(columnDefinition = "TEXT")
  • 장점: 컬럼명, 제약조건, 타입 등 세밀한 제어
  • 단점: 생략 시 필드명으로 컬럼 생성
  • 사용 빈도: 매우 높음 (5/5)

2.6 @Transient

  • 설명: 영속성에서 제외할 필드 지정
  • 사용 예시:
    @Transient 
    private String tempData;
  • 장점: 계산 필드, 임시 데이터 등 저장 불필요한 필드 처리
  • 단점: DB에 저장되지 않음
  • 사용 빈도: 낮음 (2/5)

2.7 @Enumerated

  • 설명: Enum 타입 매핑 방식 지정
  • 사용 예시:
    @Enumerated(EnumType.STRING)
    private UserType userType;
  • 장점: Enum을 DB에 저장, STRING 권장
  • 단점: ORDINAL 사용 시 순서 변경 위험
  • 사용 빈도: 높음 (4/5)

2.8 @Temporal

  • 설명: 날짜/시간 타입 매핑 (Java 8+에서는 거의 사용 안 함)
  • 사용 예시:
    @Temporal(TemporalType.TIMESTAMP)
  • 장점: 레거시 코드 호환
  • 단점: Java 8+ LocalDateTime 사용 시 불필요
  • 사용 빈도: 매우 낮음 (1/5)

2.9 @Lob

  • 설명: 대용량 데이터 타입 매핑
  • 사용 예시:
    @Lob 
    private String content;
    @Lob 
    private byte[] image;
  • 장점: TEXT, BLOB 타입 매핑
  • 단점: 성능 고려 필요
  • 사용 빈도: 보통 (3/5)

2.10 @Version

  • 설명: 낙관적 잠금(Optimistic Locking)을 위한 버전 필드
  • 사용 예시:
    @Version 
    private Long version;
  • 장점: 동시성 제어, 낙관적 잠금
  • 단점: 업데이트 시 버전 체크 필요
  • 사용 빈도: 낮음 (2/5)

3. 관계 매핑 어노테이션

3.1 @OneToOne

  • 설명: 1:1 관계 매핑
  • 사용 예시:
    @OneToOne(mappedBy = "user")
    private UserProfile profile;
  • 장점: 단일 관계 표현
  • 단점: 양방향 시 mappedBy 필요
  • 사용 빈도: 보통 (3/5)

3.2 @OneToMany

  • 설명: 1:N 관계 매핑
  • 사용 예시:
    @OneToMany(mappedBy = "rental", cascade = CascadeType.ALL)
    private List<TbRentalHall> halls;
  • 장점: 컬렉션으로 여러 객체 관리
  • 단점: N+1 문제 주의, mappedBy 또는 @JoinColumn 필요
  • 사용 빈도: 높음 (4/5)

3.3 @ManyToOne

  • 설명: N:1 관계 매핑
  • 사용 예시:
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "rental_no")
    private TbRental rental;
  • 장점: 가장 많이 사용, FK 매핑
  • 단점: 지연 로딩 설정 중요
  • 사용 빈도: 매우 높음 (5/5)

3.4 @ManyToMany

  • 설명: N:N 관계 매핑
  • 사용 예시:
    @ManyToMany
    @JoinTable(name = "user_role")
    private List<Role> roles;
  • 장점: 복잡한 관계 표현
  • 단점: 중간 테이블 생성, 실제로는 중간 엔티티 권장
  • 사용 빈도: 낮음 (2/5)

3.5 @JoinColumn

  • 설명: 외래키 컬럼 지정
  • 사용 예시:
    @JoinColumn(name = "rental_no", nullable = false)
  • 장점: FK 컬럼명 명시적 지정
  • 단점: 생략 시 기본명 사용
  • 사용 빈도: 매우 높음 (5/5)

3.6 @JoinTable

  • 설명: 중간 테이블 지정 (ManyToMany)
  • 사용 예시:
    @JoinTable(name = "user_role", 
      joinColumns = @JoinColumn(name = "user_id"),
      inverseJoinColumns = @JoinColumn(name = "role_id"))
  • 장점: 중간 테이블 커스터마이징
  • 단점: ManyToMany에서만 사용
  • 사용 빈도: 낮음 (2/5)

관계 매핑 옵션

fetch = FetchType.LAZY

  • 지연 로딩 (기본값: OneToMany, ManyToMany)
  • 장점: 필요한 때만 조회, 성능 향상
  • 단점: 프록시 객체 주의

fetch = FetchType.EAGER

  • 즉시 로딩 (기본값: ManyToOne, OneToOne)
  • 장점: 항상 함께 조회
  • 단점: N+1 문제, 성능 저하 가능

cascade = CascadeType.ALL

  • 모든 작업 전파
  • 장점: 연관 객체 자동 저장/삭제
  • 단점: 의도치 않은 삭제 주의

cascade = CascadeType.PERSIST

  • 저장만 전파
  • 장점: 저장 시에만 전파
  • 단점: 선택적 전파

mappedBy

  • 양방향 관계에서 연관관계 주인 지정
  • 장점: 단방향 FK 관리, 중복 방지
  • 단점: 주인 쪽에서만 수정 가능

orphanRemoval = true

  • 고아 객체 자동 삭제
  • 장점: 컬렉션에서 제거 시 자동 삭제
  • 단점: 의도치 않은 삭제 주의

4. Hibernate 특화 어노테이션

4.1 @CreationTimestamp

  • 설명: 생성 시 자동으로 현재 시간 설정
  • 사용 예시:
    @CreationTimestamp
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;
  • 장점: 자동 타임스탬프 관리
  • 단점: Hibernate 전용 (JPA 표준 아님)
  • 사용 빈도: 매우 높음 (5/5)

4.2 @UpdateTimestamp

  • 설명: 수정 시 자동으로 현재 시간 갱신
  • 사용 예시:
    @UpdateTimestamp
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;
  • 장점: 자동 타임스탬프 관리
  • 단점: Hibernate 전용
  • 사용 빈도: 매우 높음 (5/5)

4.3 @DynamicUpdate

  • 설명: 변경된 필드만 UPDATE 쿼리에 포함
  • 사용 예시:
    @DynamicUpdate
    @Entity
    public class User {}
  • 장점: 성능 최적화, 변경 필드만 업데이트
  • 단점: 약간의 오버헤드
  • 사용 빈도: 보통 (3/5)

4.4 @DynamicInsert

  • 설명: null이 아닌 필드만 INSERT 쿼리에 포함
  • 사용 예시:
    @DynamicInsert
    @Entity
    public class User {}
  • 장점: 성능 최적화
  • 단점: 약간의 오버헤드
  • 사용 빈도: 낮음 (2/5)

4.5 @Where

  • 설명: 엔티티 조회 시 자동 WHERE 조건 추가
  • 사용 예시:
    @Where(clause = "is_deleted = 0")
  • 장점: 논리 삭제 자동 처리
  • 단점: 모든 쿼리에 적용됨
  • 사용 빈도: 보통 (3/5)

4.6 @SQLDelete

  • 설명: 삭제 시 실행할 커스텀 SQL 지정
  • 사용 예시:
    @SQLDelete(sql = "UPDATE tb_user SET is_deleted = 1 WHERE seq_no = ?")
  • 장점: 논리 삭제 구현
  • 단점: Hibernate 전용
  • 사용 빈도: 보통 (3/5)

4.7 @SQLInsert

  • 설명: 삭제 시 실행할 커스텀 SQL 지정
  • 사용 예시:
    @SQLInsert(sql = "...")
  • 장점: 복잡한 INSERT 로직
  • 단점: 거의 사용 안 함
  • 사용 빈도: 매우 낮음 (1/5)

4.8 @Formula

  • 설명: 읽기 전용 계산 필드
  • 사용 예시:
    @Formula("(SELECT COUNT(*) FROM orders WHERE user_id = seq_no)")
    private Long orderCount;
  • 장점: DB 레벨 계산
  • 단점: 읽기 전용, 쿼리 복잡도 증가
  • 사용 빈도: 낮음 (2/5)

5. 생명주기 어노테이션

5.1 @PrePersist

  • 설명: 엔티티 저장 전 실행
  • 사용 예시:
    @PrePersist
    public void prePersist() {
      this.createdAt = LocalDateTime.now();
    }
  • 장점: 저장 전 자동 처리
  • 단점: 트랜잭션 내에서만 동작
  • 사용 빈도: 보통 (3/5)

5.2 @PostPersist

  • 설명: 엔티티 저장 후 실행
  • 사용 예시:
    @PostPersist
    public void postPersist() {
      log.info("Saved: {}", this);
    }
  • 장점: 저장 후 로깅 등
  • 단점: 트랜잭션 내에서만 동작
  • 사용 빈도: 낮음 (2/5)

5.3 @PreUpdate

  • 설명: 엔티티 수정 전 실행
  • 사용 예시:
    @PreUpdate
    public void preUpdate() {
      this.updatedAt = LocalDateTime.now();
    }
  • 장점: 수정 전 자동 처리
  • 단점: 트랜잭션 내에서만 동작
  • 사용 빈도: 보통 (3/5)

5.4 @PostUpdate

  • 설명: 엔티티 수정 후 실행
  • 사용 예시:
    @PostUpdate
    public void postUpdate() {
      log.info("Updated: {}", this);
    }
  • 장점: 수정 후 로깅 등
  • 단점: 트랜잭션 내에서만 동작
  • 사용 빈도: 낮음 (2/5)

5.5 @PreRemove

  • 설명: 엔티티 삭제 전 실행
  • 사용 예시:
    @PreRemove
    public void preRemove() {
      log.info("Removing: {}", this);
    }
  • 장점: 삭제 전 검증 등
  • 단점: 트랜잭션 내에서만 동작
  • 사용 빈도: 낮음 (2/5)

5.6 @PostRemove

  • 설명: 엔티티 삭제 후 실행
  • 사용 예시:
    @PostRemove
    public void postRemove() {
      log.info("Removed: {}", this);
    }
  • 장점: 삭제 후 로깅 등
  • 단점: 트랜잭션 내에서만 동작
  • 사용 빈도: 낮음 (2/5)

5.7 @PostLoad

  • 설명: 엔티티 조회 후 실행
  • 사용 예시:
    @PostLoad
    public void postLoad() {
      this.fullName = firstName + " " + lastName;
    }
  • 장점: 조회 후 계산 필드 설정
  • 단점: 매 조회마다 실행
  • 사용 빈도: 낮음 (2/5)

실제 프로젝트 사용 예시

TbRental 엔티티 분석

@Getter @Setter                    // Lombok: getter/setter 자동 생성
@NoArgsConstructor                 // Lombok: JPA 필수 기본 생성자
@AllArgsConstructor               // Lombok: 모든 필드 생성자
@Builder                          // Lombok: 빌더 패턴
@Entity                           // JPA: 엔티티 선언
@Table(name = "tb_rental")        // JPA: 테이블명 지정
public class TbRental {

    @Id                           // JPA: 기본키
    @GeneratedValue(strategy = GenerationType.IDENTITY)  // JPA: 자동 증가
    @Column(name = "seq_no")      // JPA: 컬럼명 매핑
    private Long seqNo;

    @Column(name = "rental_name", nullable = false, length = 255)
    private String rentalName;

    @Column(name = "rental_description", columnDefinition = "TEXT")
    private String rentalDescription;

    @Column(name = "rental_active", length = 2)
    @Builder.Default              // Lombok: Builder 기본값
    private String rentalActive = "Y";

    @CreationTimestamp            // Hibernate: 생성 시간 자동 설정
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;

    @UpdateTimestamp              // Hibernate: 수정 시간 자동 갱신
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;
}

TbUser 엔티티 분석

@Getter @Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode(of = "seqNo")  // Lombok: seqNo만으로 equals/hashCode
@Entity
@Table(name = "tb_user")
public class TbUser {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "seq_no")
    private Long seqNo;

    @Column(name = "user_id", nullable = false, length = 50, unique = true)
    private String userId;

    @Enumerated(EnumType.STRING)  // JPA: Enum을 문자열로 저장
    @Column(name = "user_type", nullable = false, length = 20)
    private UserType userType;

    @CreationTimestamp
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;

    @UpdateTimestamp
    @Column(name = "updated_at", nullable = false)
    private LocalDateTime updatedAt;
}

권장 사용 패턴

1. 엔티티 클래스 기본 구조

@Getter @Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@Table(name = "tb_xxx")
public class TbXxx {
    // 필드들...
}

2. 기본키 설정

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "seq_no")
private Long seqNo;

3. 타임스탬프 필드

@CreationTimestamp
@Column(name = "created_at", updatable = false)
private LocalDateTime createdAt;

@UpdateTimestamp
@Column(name = "updated_at")
private LocalDateTime updatedAt;

4. 관계 매핑 (ManyToOne)

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "rental_no", nullable = false)
private TbRental rental;

5. Enum 필드

@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false, length = 20)
private UserStatus status;

주의사항

1. Lombok과 JPA 함께 사용 시

  • @NoArgsConstructor는 필수 (JPA 요구사항)
  • @Builder 사용 시 @AllArgsConstructor 필요
  • @Builder.Default로 기본값 설정

2. 관계 매핑

  • @ManyToOne은 기본적으로 EAGER, LAZY로 변경 권장
  • @OneToMany는 기본적으로 LAZY
  • 양방향 관계 시 mappedBy로 주인 지정

3. 성능 최적화

  • 불필요한 EAGER 로딩 지양
  • @DynamicUpdate로 변경 필드만 업데이트
  • @Where로 논리 삭제 자동 처리

4. 타임스탬프

  • @CreationTimestamp는 updatable = false 설정
  • @UpdateTimestamp는 자동 갱신되므로 수동 설정 불필요

참고 자료

반응형