반응형
JPA 엔티티 어노테이션 완전 정리 가이드
목차
- Lombok 어노테이션
- JPA 기본 어노테이션
- 관계 매핑 어노테이션
- Hibernate 특화 어노테이션
- 생명주기 어노테이션
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는 자동 갱신되므로 수동 설정 불필요
참고 자료
- JPA 공식 문서: https://jakarta.ee/specifications/persistence/
- Hibernate 공식 문서: https://hibernate.org/orm/documentation/
- Lombok 공식 문서: https://projectlombok.org/
- Spring Data JPA 문서: https://spring.io/projects/spring-data-jpa
반응형
'JAVA' 카테고리의 다른 글
| @NoArgsConstructor 가 뭔데? (0) | 2025.12.01 |
|---|---|
| objectMapper.readValue의 class를 똑바로 적어야 하는 이유 (0) | 2025.11.26 |
| FOR문은 효율적일까? ExecutorService 사용법 (0) | 2024.05.02 |
| StringBuilder 를 왜 쓸까? (0) | 2024.01.07 |
| ajax 데이터 제어 @RequestParam @RequestBody (0) | 2022.08.21 |