Spring boot

버전 3 -1 .연관관계 설정하기

mynote6676 2025. 6. 24. 20:31

| 게시글을 볼 때 작성자 정보도 함께 보고 싶다면 어떻게 해야 할까요?

 

= 객체지향 사고 + 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