| 게시글을 볼 때 작성자 정보도 함께 보고 싶다면 어떻게 해야 할까요?
= 객체지향 사고 + DB JOIN 의 개념입니다.
샘플 데이터
-- 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());
V2 방식의 문제점
// V2 - 단순 문자열 방식
public class Board {
private String username; // "홍길동"
}
// 문제 상황들:
// 1. "홍길동"이 실제 회원인지 확인 불가
// 2. 작성자의 이메일 정보를 알고 싶다면?
// 3. 작성자가 이름을 변경했다면?
// 4. 같은 이름의 사용자가 여러 명이라면?
데이터베이스 관점에서 이해하기
-- 게시글과 작성자 정보를 함께 조회하고 싶을 때
SELECT
b.title,
b.content,
u.username,
u.email
FROM board_tb b
JOIN user_tb u ON b.user_id = u.id; --JOIN이 필요한 순간!
객체지향 관점에서 이해하기
// 현실에서 생각해보기
Class 학생 {
String 이름;
School 소속학교; // 학생은 학교에 "속해있다" (연인관계)
}
class School {
String 학교명;
String 주소;
}
// 사용 예시
학생 철수 = new 학생("철수", 서울대학교);
System.out.println("철수의 학교 : " + 철수.소속학교.학교명); // 객체 참조!
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;
@NoArgsconstructor
@Data
@Table(name = "user_tb")
@Entity
public class User {
@Id // pk설정
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 사용자 이름 중복 방지를 위한 유니크 제약 설정
@Column(unique= true)
private String username;
private String password;
private String email;
// now() -> x
// 엔티티가 영속화 될때 자동으로 pc 현재시간을 설정해 준다.
@creationTimestamp
private Timestamp createdAt;
//객체 생성시 가독성과 안정성 향상
@Builder
public User(Long id, String username, String password, String email, Timestamp createAt){
this.id = id;
this.username = username;
this.password = password;
this.email = email;
this.createdAt =createdAt;
}
}
Hibernate:
create table user_tb (
created_at datetime(6),
id bigint not null auto_increment,
email varchar(255),
password varchar(255),
username varchar(255),
primary key (id)
) engine=InnoDB
Hibernate:
alter table user_tb
add constraint UKlvx22t2upvjxxc86vf5daxc71 unique (username)
Board 엔티티 수정 -> User 엔티티와 연관관계 설정
package com.tenco.blog.board;
import com.tenco.blog.user.User;
import com.tenco.blog.utils.MyDateUtil;
import jakarta.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import java.sql.Timestamp;
@NoArgsConstructor
// 기본 생성자 - JPA에서 엔티티는 기본 생성자가 필요
@Data
@Table(name = "board_tb")
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
// V2에서 사용했던 방식
// private String username;
// V3 에서 Board 엔티티는 User 엔티티와 연관관계가 성립이 된다
// 다대일
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id") // 외래키 컬러명 명시
private User user;
@CreationTimestamp
private Timestamp createdAt;
// 생성자 만들어 주기
// public Board(String title, String content, String username) {
// this.title = title;
// this.content = content;
// this.username = username;
// }
public String getTime() {
return MyDateUtil.timestampFormat(createdAt);
}
}
N + 1
Hibernate:
select
b1_0.id,
b1_0.content,
b1_0.created_at,
b1_0.title,
b1_0.user_id
from
board_tb b1_0
order by
b1_0.id desc
Hibernate:
select
u1_0.id,
u1_0.created_at,
u1_0.email,
u1_0.password,
u1_0.username
from
user_tb u1_0
where
u1_0.id=?
728x90
'Spring boot' 카테고리의 다른 글
버전 3 - 2. 게시 글 상세보기 - 연관 관계 기본 활용 (0) | 2025.06.25 |
---|---|
버전 3 - 빌더 패턴에 대해 알아 보기 (0) | 2025.06.24 |
버전-2 -5. 게시글 삭제하기 V2 - Persistence Context와 영속성 관리 (0) | 2025.06.24 |
버전 2 -4.게시글 수정하기 V2 - Persistence Context와 Dirty Checking 활용 (0) | 2025.06.24 |
버전 2- # 3. 게시글 상세보기 만들기 - Persistence Context와 1차 캐시 활용 (0) | 2025.06.24 |