이 파일의 학습 목적
02c — @Entity · JPA · @ManyToOne — DB와 Java를 연결하는 방법
Board 테이블이 User 테이블을 참조하는데, Java 코드에서는 board.getUser().getNickname()처럼 객체로 접근한다.
DB의 FK(외래키)와 Java의 객체 참조를 연결해주는 것이 JPA다. 02c는 Board·User Entity 구조와 @ManyToOne 연관관계를 완전히 이해하는 것이 목표다.
이 파일에서 배울 3가지
- ① @Entity 어노테이션 완전 해부 — @Id, @GeneratedValue, @Column
- ② @PrePersist · @PreUpdate — 저장/수정 시 자동 시간 입력
- ③ @ManyToOne · @JoinColumn — 게시글↔유저 연관관계
프로젝트 코드 연결
- · Board.java —
@ManyToOne User user
- ·
board.getUser().getNickname() — toDto()에서
- ·
deleteByUser(User user) — 유저 삭제 시 게시글 먼저
시리즈 순서:
02a·02b →
02c ← 지금 여기
→ 03a 동기·비동기·Ajax
→ 03b CORS·axios
01 — @Entity 어노테이션 완전 해부
DB 테이블과 Java 클래스를 연결하는 JPA 핵심 어노테이션들
🗂️
DB 테이블 ↔ Java 클래스 매핑
JPA
📋 비유 — 엑셀 시트와 Java 클래스
DB 테이블 = 엑셀 시트 (행·열로 데이터 저장)
Entity 클래스 = 시트 한 행을 담는 Java 객체
@Entity 붙이면 → JPA가 "이 클래스는 DB 테이블이야" 인식 → 테이블 자동 생성
Java — 프로젝트 User Entity 전체 해부
@Entity
@Table(name = "users")
@Getter
@NoArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(nullable = false)
private String password;
private String nickname;
private String role;
private LocalDateTime createdAt;
}
DB 테이블 (users)
id BIGINT AUTO_INCREMENT PK
username VARCHAR UNIQUE NOT NULL
password VARCHAR NOT NULL
nickname VARCHAR
role VARCHAR
created_at DATETIME
↔
Java Entity (User.java)
@Id Long id
@Column(unique) String username
@Column(nullable=false) String password
String nickname
String role
LocalDateTime createdAt
| 어노테이션 | 역할 | SQL 대응 |
| @Entity | 이 클래스는 DB 테이블 | CREATE TABLE |
| @Table(name="users") | 테이블명 지정 | CREATE TABLE users |
| @Id | Primary Key | PRIMARY KEY |
| @GeneratedValue | 자동 증가 | AUTO_INCREMENT |
| @Column(unique=true) | 중복 불가 | UNIQUE |
| @Column(nullable=false) | null 불가 | NOT NULL |
💡 @NoArgsConstructor가 Entity에 필수인 이유
JPA가 DB에서 데이터를 꺼낼 때 빈 객체를 먼저 만들고 값을 채움
→ 파라미터 없는 기본 생성자가 없으면 JPA가 객체를 만들 수 없어서 오류 발생
02 — @PrePersist · @PreUpdate
INSERT·UPDATE 직전에 자동 실행 — 생성시간·수정시간 자동 처리
⏰
JPA 라이프사이클 콜백
Lifecycle
📸 비유 — 자동 타임스탬프
사진 찍을 때 날짜·시간이 자동으로 찍히듯
@PrePersist = INSERT(저장) 직전에 자동 실행
@PreUpdate = UPDATE(수정) 직전에 자동 실행
→ 매번 수동으로 시간 설정 안 해도 됨
Java — Board Entity @PrePersist·@PreUpdate
@Entity
public class Board {
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
@PrePersist
public void prePersist() {
this.createdAt = LocalDateTime.now();
this.updatedAt = LocalDateTime.now();
}
@PreUpdate
public void preUpdate() {
this.updatedAt = LocalDateTime.now();
}
}
Java — User Entity @PrePersist — 기본 role 설정
@Entity
public class User {
private String role;
private LocalDateTime createdAt;
@PrePersist
public void prePersist() {
this.createdAt = LocalDateTime.now();
if (this.role == null)
this.role = "ROLE_USER";
}
}
💡 @PrePersist 활용 패턴
생성시간·수정시간 자동 설정 → 매번 LocalDateTime.now() 직접 안 써도 됨
기본값 설정 → role = "ROLE_USER" 자동 부여
→ Service 코드가 깔끔해짐
03 — @ManyToOne · @JoinColumn
게시글 N개 : 유저 1명 — 다대일 연관관계 · 지연로딩 vs 즉시로딩
🔗
연관관계 매핑
Relation
📝 비유 — 게시글과 작성자
게시글 여러 개(N) : 유저 한 명(1) = 다대일(ManyToOne) 관계
DB에서는 board.user_id 컬럼으로 연결
Java에서는 board.getUser()로 User 객체 직접 접근 가능
DB 테이블 관계
id | title | user_id
1 | 안녕 | 1
2 | 반가워| 1
3 | 질문 | 2
id | username
1 | hong
2 | kim
Java 객체 관계
public class Board {
@ManyToOne
@JoinColumn(name="user_id")
private User user;
}
board.getUser().getNickname();
Java — Board Entity @ManyToOne 전체 코드
@Entity
public class Board {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
private LocalDateTime createdAt;
@PrePersist
public void prePersist() {
this.createdAt = LocalDateTime.now();
}
}
| FetchType | 동작 | 권장 여부 |
| FetchType.LAZY | getUser() 호출할 때 그때서야 DB 조회 — 필요할 때만 | ✅ 권장 (성능 좋음) |
| FetchType.EAGER | Board 조회할 때 User도 같이 조회 — 항상 | ⚠️ N+1 문제 발생 가능 |
⚠️ N+1 문제란?
게시글 100개 조회 시 EAGER면 → 게시글 1번 조회 + User 100번 조회 = 101번 쿼리
LAZY면 → 필요할 때만 User 조회
→ 항상 LAZY 기본으로 쓰고, 필요할 때 fetch join으로 해결
→ 자세한 내용은 09 JPA 완전 이해에서 다룸
📌 우리 프로젝트 연관관계
Board @ManyToOne User — 게시글 N : 유저 1
Comment @ManyToOne Board — 댓글 N : 게시글 1
Comment @ManyToOne User — 댓글 N : 유저 1
Spring 기초 시리즈 — 전체 정리
02a · 02b · 02c — 이 구조가 1차·2차·3차 프로젝트 전체의 뼈대
02a
Controller·Mapping·DTO
@Controller vs @RestController
URL 매핑 어노테이션
DTO 보안·최적화
02b
Session·Service·Repository
HttpSession 로그인 흐름
3계층 역할 분리
JpaRepository 자동 쿼리
02c
Entity·JPA·연관관계
@Entity 어노테이션 해부
@PrePersist 자동 시간
@ManyToOne 연관관계
흐름 — 02 시리즈 전체 연결 — 게시글 작성 요청 처리
@PostMapping("/api/board/write")
public ResponseEntity<?> write(@RequestBody BoardDto dto) {
boardService.write(dto);
return ResponseEntity.ok("success");
}
public void write(BoardDto dto) {
Board board = new Board();
board.setTitle(dto.getTitle());
board.setUser(loginUser);
boardRepository.save(board);
}