Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
Tags
- OPP개념
- 반복문
- 생성자
- 인텔리제이 기초 설정
- java변수
- function
- JAVA기초
- While
- 컴파일
- 메서드
- 포함관계
- 인텔리제이 한글 깨짐 해결법
- 메서드 오버로딩
- multi-threading
- break문
- 접근제어지시자
- 상수
- Java
- 연관관계
- Java데이터 타입
- 집합관계
- for문
- IntelliJ IDEA
- 자바 멀티스레딩
- this예약어
- JAVA객체지향
- 시스템 환경 변수 편집
- continue문
- 형 변환
- Thread
Archives
- Today
- Total
최원종의 개발 블로그
V3 (사용자 관리 및 연관 관계 설정) -1 연관관계 설정하기 본문
User 엔티티 설계 및 생성 코드
package com.tenco.blog.user;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import java.sql.Timestamp;
@Data
@NoArgsConstructor
@Table(name = "user_tb")
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// 사용자명 중복 방지를 위한 유니크 제약 조건 설정
@Column(unique = true)
private String username;
private String password;
private String email;
// 엔티티가 영속화 될 때 자동으로 현재 시간을 주입해라 pc -> db
@CreationTimestamp
private Timestamp createdAt;
@Builder
public User(Integer id, String username, String password, String email, Timestamp createdAt) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
this.createdAt = createdAt;
}
}
주요 어노테이션 설명
@Entity"JPA가 관리하는 엔티티임을 선언" - 클래스를 DB 테이블과 매핑하겠다고 선언하는 핵심 마커.
@Table"이름표 달기" - DB에 생성될 테이블 명을 명시. (user_tb)
@Id"주민번호 부여" - 해당 필드를 테이블의 기본키(Primary Key)로 설정.
@GeneratedValue"번호 뽑기" - PK 생성 전략을 결정함. IDENTITY는 DB의 Auto-Increment를 따름.
@Column"제약 사항" - 컬럼의 속성을 정의함. unique = true는 중복 데이터를 금지함.
@CreationTimestamp"자동 기록" - 객체가 생성(INSERT)되는 시점의 시간을 자동으로 기록함.
@Builder"조립식 생성" - 생성자 인자가 많아도 가독성 있게 객체를 생성하게 돕는 패턴.
필드 및 로직 상세 분석
1. 기본키(PK) 전략 (Integer id)
GenerationType.IDENTITY를 사용하여 데이터베이스(MySQL 등)가 번호를 자동으로 할당하게 함.
개발자가 직접 ID를 관리하지 않아도 되므로 데이터 무결성이 보장됨.
2. 유니크 제약조건 (username)
@Column(unique = true) 설정을 통해 동일한 아이디를 가진 사용자의 중복 가입을 DB 레벨에서 원천 차단함.
중복 가입 시도 시 DataIntegrityViolationException이 발생함.
3. Lombok의 활용 (@Data, @NoArgsConstructor)
@Data: Getter, Setter 등을 자동 생성하여 코드 다이어트(Boilerplate 제거)를 실현함.
@NoArgsConstructor: JPA가 리플렉션을 통해 객체를 생성할 때 필요한 기본 생성자를 자동으로 만들어줌.
4. 빌더 패턴 (@Builder)
생성자에 빌더 패턴을 적용하여, 객체 생성 시 필드 순서에 상관없이 이름으로 값을 세팅할 수 있음.
코드 예시: User.builder().username("ssar").build();
게시글을 볼 때 작성자 정보도 함께 출력하는 코드(객체지향 사고 +DB JOIN의 개념)
Board 코드
package com.tenco.blog.board;
import com.tenco.blog.user.User;
import com.tenco.blog.util.MyDateUtil;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import java.sql.Timestamp;
@Data // get,set, toString ..
// @Entity - JPA가 이 클래스를 데이터베이스 테이블과 매핑하는 객체로 인식하게 설정
// 즉, 이 어노테이션이 있어야 JPA가 관리 함
@Entity
@Table(name = "board_tb")
@NoArgsConstructor
@AllArgsConstructor // 전체 멤벼 번수를 넣을 수 있는 생성자.
@Builder
public class Board {
// @id : 이 필드가 기본키임을 설정 함
@Id
// IDENTITY 전략: 데이터베이스게 기본 AUTO_INCREMENT 기능 사용
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// private String username; 삭제해야 함.
private String title;
private String content;
// 연관관계 설정 해주어야 한다.
// 다대일 연관관계 : 여러개 게시글이 하나의 사용자에게 속한다.
// FetchType 전략 : EAGER, LAZY
// EAGER - 조회시 한번에 다 들고 와라 ( 1번 게시글 조회시 한번 조인까지 해라)
// LAZY - 처음부터 Board 조회할 때 User 정보를 가져오지 마. 필요할 때 한번 더 조회 해.
@ManyToOne(fetch = FetchType.EAGER)
// @OneToMany
// @OneToOne
@JoinColumn(name = "user_id") // 외래키 컬럼명 표시 됨
private User user;
// @CreationTimestamp : 하이버네이트가 제공하는 어노테이션
// 특정 하나의 엔티티가 저장이 될 때 현재 시간을 자동으로 저장해 설정
// now() 명시할 필요 없음
// pc --> db (자동 날짜 주입)
@CreationTimestamp
private Timestamp createdAt;
// createdAt -> 포멧 하는 메서드 만들어 보기
public String getTime() {
return MyDateUtil.timestampFormat(createdAt);
}
// 수정 편의 기능 만들기
public void update(BoardRequest.UpdateDTO updateDTO) {
// this.username = updateDTO.getUsername(); 삭제 예정
this.title = updateDTO.getTitle();
this.content = updateDTO.getContent();
// 더티체킹 - 변경 감지 동작 과정
// 1. 최초 조회시 영속성 컨텍스트 1차 캐쉬에 데이터를 스냅샷으로 보관 함.
// 2. 영속화된 엔티티가(board)의 멤버 변수값이 변경이 된다면
// 1차에서 보관했던 값과 2차에서 수정된 필드값을 비교 함.
// 3. 변화가 발생이 되었다면 트랜잭션 커밋 시점에 변경된 필드값 UPDATE 쿼리 자동 생성
// 4. 물리적은 DB에 반영 됨.
}
}
연관관계 매핑
private User user;: 기존의 username 같은 단순 텍스트가 아닌 객체 자체를 필드로 가짐.
FetchType.EAGER: 게시글 조회 시 작성자(User) 정보를 즉시 조인(Join)하여 가져옴
Tip: 게시글 목록에서 작성자 이름이 매번 필요할 때 유용하지만,
실무에서는 성능 최적화를 위해 주로 LAZY를 선호함
수정 편의 메서드와 더티 체킹
update() 메서드 내부에 별도의 save() 호출이 없는 이유는 JPA의 변경 감지(Dirty Checking) 기능 덕분.
조회 시점: 영속성 컨텍스트(PC)에 엔티티가 들어오면 스냅샷을 찍어 보관함.
수정 시점: 자바 객체의 필드값(title, content)을 변경함.
커밋 시점: 트랜잭션 종료 시 스냅샷과 현재 엔티티를 비교함.
반영 시점: 변경 사항이 발견되면 JPA가 자동으로 UPDATE 쿼리를 생성하여 DB에 전송함.
db 데이터 재설정
-- User 테이블 데이터 (5명의 사용자)
INSERT INTO user_tb (username, password, email, created_at) VALUES
('admin', '1234', 'admin@blog.com', NOW()),
('ssar', '1234', 'ssar@nate.com', NOW()),
('cos', '1234', 'cos@gmail.com', NOW()),
('hong', '1234', 'hong@naver.com', NOW()),
('kim', '1234', 'kim@daum.net', NOW());
-- 2단계: Board 테이블 데이터 (10개의 게시글)
-- 주의: user_id는 위에서 생성된 사용자의 id를 참조
-- admin 사용자가 작성한 게시글 (3개)
INSERT INTO board_tb (title, content, user_id, created_at) VALUES
('블로그 개설을 환영합니다!', '안녕하세요! 새로운 블로그가 오픈했습니다. 많은 관심과 참여 부탁드립니다.', 1, NOW()),
('공지사항: 이용수칙 안내', '블로그 이용 시 지켜야 할 기본적인 수칙들을 안내드립니다. 건전한 소통 문화를 만들어가요.', 1, NOW()),
('업데이트 소식', '새로운 기능들이 추가되었습니다. 댓글 기능과 좋아요 기능을 곧 만나보실 수 있습니다.', 1, NOW());
-- ssar 사용자가 작성한 게시글 (3개)
INSERT INTO board_tb (title, content, user_id, created_at) VALUES
('Spring Boot 학습 후기', 'Spring Boot를 처음 배우면서 느낀 점들을 공유합니다. JPA가 정말 편리하네요!', 2, NOW()),
('JPA 연관관계 정리노트', '오늘 배운 @ManyToOne, @OneToMany 연관관계에 대해 정리해봤습니다. 헷갈리는 부분이 많아요.', 2, NOW()),
('코딩테스트 문제 추천', '백준과 프로그래머스에서 풀어볼 만한 문제들을 추천드립니다. 알고리즘 공부 화이팅!', 2, NOW());
-- cos 사용자가 작성한 게시글 (2개)
INSERT INTO board_tb (title, content, user_id, created_at) VALUES
('React vs Vue 비교', '프론트엔드 프레임워크 선택에 고민이 많았는데, 각각의 장단점을 비교해봤습니다.', 3, NOW()),
('개발자 취업 팁 공유', '신입 개발자로 취업하면서 도움이 되었던 팁들을 공유합니다. 포트폴리오가 중요해요!', 3, NOW());
-- hong 사용자가 작성한 게시글 (1개)
INSERT INTO board_tb (title, content, user_id, created_at) VALUES
('첫 번째 게시글입니다', '안녕하세요! 블로그에 처음 글을 올려봅니다. 앞으로 자주 소통해요~', 4, NOW());
-- kim 사용자가 작성한 게시글 (1개)
INSERT INTO board_tb (title, content, user_id, created_at) VALUES
('맛집 추천 - 강남역 근처', '강남역 근처에서 점심 먹기 좋은 맛집들을 추천드립니다. 가성비도 좋아요!', 5, NOW());
'Spring boot 입문' 카테고리의 다른 글
| V3-3 게시글 목록보기(연산관계로 작성자 정보 표시) (0) | 2026.05.11 |
|---|---|
| V3-2 게시글 상세보기 (연관관계 기본 활용) (0) | 2026.05.11 |
| V2(PersistentContext) 게시글 수정하기 - Persistence Context와 Dirty Checking 활용 (0) | 2026.05.11 |
| V2(PersistentContext) 게시글 삭제하기 - Persistence Context와 영속성 관리 (0) | 2026.05.07 |
| V2(PersistentContext) 게시글 상세보기 만들기 - Persistence Context와 1차 캐시 활용 (0) | 2026.05.07 |
