본문 바로가기

Spring boot/Blog 프로젝트 만들기(JPA)

완성 코드 STEP 02 - 연관 관계 매핑: User와 Board 엔티티 ( JPA API , JPQL 쿼리 사용, 인증(세션 로직 추가 )

Board 엔티티에 User와의 연관 관계를 설정

수정된 Board 엔티티 코드
package com.tenco.blog_v1.board;

import com.tenco.blog_v1.user.User;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.sql.Timestamp;

@NoArgsConstructor
@Entity
@Table(name = "board_tb")
@Data
public class Board {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 기본키 전략 db 위임
    private Integer id;
    private String title;
    private String content;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id")
    private User user; // 게시글 작성자 정보

    // created_at 컬럼과 매핑하며, 이 필드는 데이터 저장시 자동으로 설정 됨
    @Column(name = "created_at", insertable = false, updatable = false)
    private Timestamp createdAt;

    @Builder
    public Board(Integer id, String title, String content, User user, Timestamp createdAt) {
        this.id = id;
        this.title = title;
        this.content = content;
        this.user = user;
        this.createdAt = createdAt;
    }

}

코드 설명

  • @Entity: 이 클래스가 JPA 엔티티임을 나타냅니다.
  • @Table(name = "board_tb"): 엔티티와 매핑될 테이블 이름을 지정합니다.
  • @Id, @GeneratedValue: 기본 키 필드를 설정합니다.
  • @ManyToOne(fetch = FetchType.LAZY):
    • Board 엔티티가 User 엔티티와 다대일 관계임을 나타냅니다.
    • 지연 로딩(LAZY): 실제로 user 필드가 사용될 때까지 로딩을 지연시킵니다.
  • @JoinColumn(name = "user_id"):
    • 외래 키 컬럼의 이름을 user_id로 지정합니다.
    • 이 컬럼을 통해 User 엔티티와 연결됩니다.
  • private User user;: 작성자 정보를 나타내는 필드입니다.

 

User 엔티티 작성하기

User 엔티티에 Board와의 연관 관계를 설정하여, 사용자가 작성한 게시글 목록을 가져올 수 있도록 합니다.
package com.tenco.blog_v1.user;

import com.tenco.blog_v1.board.Board;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;

import java.sql.Timestamp;
import java.util.List;

@NoArgsConstructor
@Data
@Entity
@Table(name = "user_tb")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(unique = true) // 유니크 제약 조건 설정
    private String username;
    private String password;
    private String email;

    @CreationTimestamp // 엔티티 생성시 자동으로 현재 시간 입력
    private Timestamp createdAt;

    // 단방향, 양방향 매핑(mappedBy)
    // @OneToMany(mappedBy = "user", fetch = FetchType.LAZY) // 지연 로딩 설정
    @OneToMany(mappedBy = "user", fetch = FetchType.EAGER) // 즉시 로딩 설정
    private List<Board> boards;

    @Builder
    public User(Integer id, String username, String password, String email, Timestamp createdAt, List<Board> boards) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.email = email;
        this.createdAt = createdAt;
        this.boards = boards;
    }

}

코드 설명

  • @OneToMany(mappedBy = "user", fetch = FetchType.LAZY):
    • User 엔티티가 Board 엔티티와 일대다 관계임을 나타냅니다.
    • mappedBy = "user": Board 엔티티의 user 필드에 의해 매핑됨을 나타냅니다.
    • 지연 로딩(LAZY): 실제로 boards 필드가 사용될 때까지 로딩을 지연시킵니다.
  • private List<Board> boards;: 사용자가 작성한 게시글 목록을 저장합니다.

 

 

연관 관계가 설정된 엔티티에 데이터를 삽입하여 실제로 어떻게 매핑되는지 확인.

샘플 데이터 입력
-- 사용자 데이터 삽입
INSERT INTO user_tb(username, password, email, created_at) VALUES('길동', '1234', 'a@nate.com', NOW());
INSERT INTO user_tb(username, password, email, created_at) VALUES('둘리', '1234', 'b@nate.com', NOW());
INSERT INTO user_tb(username, password, email, created_at) VALUES('마이콜', '1234', 'c@nate.com', NOW());

-- 게시글 데이터 삽입
INSERT INTO board_tb(title, content, user_id, created_at) VALUES('제목1', '내용1', 1, NOW());
INSERT INTO board_tb(title, content, user_id, created_at) VALUES('제목2', '내용2', 1, NOW());
INSERT INTO board_tb(title, content, user_id, created_at) VALUES('제목3', '내용3', 2, NOW());
INSERT INTO board_tb(title, content, user_id, created_at) VALUES('제목4', '내용4', 3, NOW());

user_id 컬럼을 통해 Board와 User가 연관 관계를 맺고 있다.

 

 

 

Hibernate가 생성한 DDL
Hibernate: 
    drop table if exists board_tb cascade 
Hibernate: 
    drop table if exists user_tb cascade 
Hibernate: 
    create table board_tb (
        id integer generated by default as identity,
        user_id integer,
        created_at timestamp(6),
        content varchar(255),
        title varchar(255),
        primary key (id)
    )
Hibernate: 
    create table user_tb (
        id integer generated by default as identity,
        created_at timestamp(6),
        email varchar(255),
        password varchar(255),
        username varchar(255) unique,
        primary key (id)
    )
Hibernate: 
    alter table if exists board_tb 
       add constraint FKgxwryj58kh66twbp656wo5gnn 
       foreign key (user_id) 
       references user_tb

board_tb 테이블에 user_id 컬럼이 외래 키(Foreign Key)로 설정되어 user_tb 테이블의 id 컬럼과 연관된다.

 

 

 

4. 핵심 개념 정리

1) 연관 관계 매핑 설정

  • @ManyToOne: Board 엔티티에서 User 엔티티와의 다대일 관계를 설정한다.
  • @OneToMany: User 엔티티에서 Board 엔티티와의 일대다 관계를 설정한다.
  • mappedBy: 연관 관계의 주인을 설정할 때 사용하며, 연관 관계의 주인이 아닌 쪽에서 사용한다.

2) 지연 로딩 (FetchType.LAZY)

  • 지연 로딩(LAZY): 연관된 엔티티를 실제로 사용할 때까지 데이터베이스 조회를 지연시킨다.
  • 즉시 로딩(EAGER): 엔티티가 로딩될 때 연관된 엔티티도 함께 로딩한다.
  • 사용 이유: 불필요한 데이터 로딩을 방지하여 성능을 최적화하기 위해 사용한다.

3) @JoinColumn 어노테이션

  • 역할: 외래 키 컬럼을 명시적으로 지정하여, 연관 관계를 매핑한다.
  • 사용 위치: 연관 관계의 주인(Owner) 쪽 엔티티의 필드에 적용다.
728x90