도슐랭스타
ReadingRecord 엔티티 생성 본문
DB와 매핑될 클래스 생성.
POST로 받을 책 내용들 저장하는 구조.
파일 위치
src/main/java/your_package_name/domain/ReadingRecord.java
domain은 모델 객체를 넣는 일반적인 디렉터리명임.
ReadingRecord.java
package me.dodo.readingnotes.domain;
import jakarta.persistence.*;
import java.time.LocalDate;
@Entity //이 클래스가 JPA 엔티티임을 선언. DB 테이블과 매핑됨
@Table(name = "reading_record") //DB에서 이 엔티티가 매핑될 테이블 이름을 지정함
public class ReadingRecord {
@Id //이 필드(id)가 **기본 키(PK)**임을 나타냄
//기본 키의 값을 DB가 **자동 증가(Auto Increment)**로 생성하도록 지정함
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String title;
private String author;
private LocalDate date;
private String content;
// 기본 생성자 (JPA 필수)
public ReadingRecord() {}
// 전체 필드 생성자
public ReadingRecord(String title, String author, LocalDate date, String content) {
this.title = title;
this.author = author;
this.date = date;
this.content = content;
}
// Getter / Setter
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
여기서 사용하는 어노테이션
@Entity - 이 클래스가 JPA 엔티티임을 선언. DB 테이블과 매핑됨
@Table(name = "reading_record") - DB에서 이 엔티티가 매핑될 테이블 이름을 지정함
@Id - 이 필드(id)가 '기본 키(PK)'임을 나타냄
@GeneratedValue(strategy = GenerationType.IDENTITY) - 기본 키의 값을 DB가 '자동 증가(Auto Increment)'로 생성하도록 지정함
질문
1. @Id에서 다른 필드로 기본키를 설정하려면?
@Entity
@Table(name = "reading_record")
public class ReadingRecord {
@Id // 이 필드가 기본 키!
private String title;
private String author;
private LocalDate date;
public ReadingRecord() {}
public ReadingRecord(String title, String author, LocalDate date) {
this.title = title;
this.author = author;
this.date = date;
}
// Getter / Setter 생략
}
복합키를 사용하고 싶으면?
@IdClass(BookId.class) // 또는 @EmbeddedId
@Entity
public class ReadingRecord {
@Id
private String title;
@Id
private String author;
// ...
}
2. 왜 int가 아니라 Long을 사용하는지?
int -> 기본형(primitive type), null 값을 가질 수 없음
Long -> 객체형(wrapper type), null 값 허용됨
- JPA에서 @Id 필드 값은 저장 전까지 null 상태일 수 있음 → int는 안 됨
- Long은 객체형이라서 null이 가능하고,
DB에 저장되면서 자동 생성된 ID가 할당되기 전까지도 문제 없이 사용할 수 있음.
4. LocalDate가 뭐지?
LocalDate는 Java의 날짜 클래스 중 하나로 날짜만 표현함. (예: 2025-04-09)
시간 정보 없음 (10:30:00 같은 시간은 없음)
5. public ReadingRecord() {} 기본 생성자가 JPA에서 필수??
JPA는 내부적으로 객체를 만들 때 리플렉션(Reflection) 을 사용해
new ReadingRecord() 형태로 객체를 자동 생성함.
따라서, JPA 엔티티 클래스에는 반드시 기본 생성자가 있어야 함!
리플렉션(Reflection) 이란?
자바에서 "클래스를 마치 유리처럼 들여다보는 능력"
리플렉션을 사용하면:
- 클래스 이름을 문자열로 받아서
- 생성자, 메서드, 필드를 읽어오고
- 직접 객체를 new 없이 만드는 것처럼 만들 수 있음.
★리플렉션으로 객체를 만들 땐 가장 쉽고 안정적인 방법이 '매개변수가 없는 생성자'를 호출하는 것임.
Class<?> clazz = ReadingRecord.class;
Object obj = clazz.getDeclaredConstructor().newInstance(); // <- 기본 생성자 필요!
만약 기본 생성자가 없으면?
JPA는 객체를 만들 수 없고, 오류가 남.
JPA를 사용하지 않으면
ReadingRecord record = new ReadingRecord("해리포터", "J.K. 롤링", LocalDate.of(2025, 4, 9));
직접 DB에 있는 값을 위의 코드처럼 하나하나 적어서 자바 객체로 바꾸어야함. 매우 비효율적이고 귀찮군.
어차피 내가 직접 다 적어서 만들어야 하기 때문에 기본 생성자를 만들지 않아도 상관 없음..ㅋ
JPA를 사용하면
ReadingRecord record = repository.findById(1L).orElse(null);
JPA가 알아서 DB를 가져와서 자동으로 그 값을 자바 객체로 만들어줌!
이때! JPA가 어떤 생성자가 있는지, 어떤 값을 넣어야 할지 미리 모르니까 "리플렉션(Reflection)"을 사용함.
'Spring Boot project' 카테고리의 다른 글
DTO 클래스 생성 Request, Response (1) | 2025.04.13 |
---|---|
ReadingRecordController 생성, get/post Test (1) | 2025.04.12 |
ReadingRecordService 생성 (0) | 2025.04.11 |
ReadingRecordRepository 생성 (0) | 2025.04.10 |
환경설정 (0) | 2025.04.09 |