[v2] Spring 게시판 조금 알고 따라하기-1

테이블 추가 생성 및 외래키 설정
HootJem's avatar
Aug 21, 2024
[v2] Spring 게시판 조금 알고 따라하기-1
일반적으로 프로젝트에서는 controller, repository와 같은 레이어별로 패키지를 나누지만, 이 경우 테이블별로 패키지를 구성했습니다.
일반적으로 프로젝트에서는 controller, repository와 같은 레이어별로 패키지를 나누지만, 이 경우 테이블별로 패키지를 구성했습니다.
 

1. user 테이블 생성

package shop.mtcoding.blog.user; import jakarta.persistence.*; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import java.sql.Timestamp; @Setter @Getter @Table(name = "user_tb") @NoArgsConstructor @Entity public class User { @GeneratedValue(strategy = GenerationType.IDENTITY) @Id private Integer id; @Column(unique = true, nullable = false) private String username; //아이디 @Column(nullable = false) private String password; @Column(nullable = false) private String email; 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; } }
위 코드를 실행한 후 콘솔을 확인하면, user_tb 테이블이 정상적으로 생성된 것을 확인할 수 있습니다.
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, created_at timestamp(6), content varchar(255) not null, title varchar(255) not null, primary key (id)) Hibernate: create table user_tb (id integer generated by default as identity, created_at timestamp(6), email varchar(255) not null, password varchar(255) not null, username varchar(255) not null unique, primary key (id))
 
이제 BoardUser 테이블 간의 외래 키 관계를 설정해보겠습니다.
 
notion image
@ManyToOne 어노테이션은 외래 키 관계를 설정할 때 사용됩니다.
package shop.mtcoding.blog.board; import jakarta.persistence.*; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import shop.mtcoding.blog.user.User; import java.sql.Timestamp; @NoArgsConstructor // 빈생성자 @Getter // private 설정이기 때문에 게터, 세터가 필요함 @Setter @Table(name = "board_tb") @Entity // DB에서 조회하면 자동 매핑이 됨 public class Board { @GeneratedValue(strategy = GenerationType.IDENTITY) // Auto_increment 열의 증가를 자동으로 시켜줌 @Id // PK (DB 테이블의 기준이 되는 키를 설정하는것) private Integer id; @Column(nullable = false) private String title; @Column(nullable = false) private String content; private Timestamp createdAt; @ManyToOne private User user; // 생성자 @Builder public Board(Integer id, String title, String content, Timestamp createdAt) { this.id = id; this.title = title; this.content = content; this.createdAt = createdAt; } }
 
notion image
이후 H2 콘솔에서 테이블 구조를 확인하면, user_id 외래 키 컬럼이 추가된 것을 확인할 수 있습니다.

2. 더미 데이터 삽입

data.sql 파일을 수정하여 더미 데이터를 삽입합니다.
insert into user_tb(username, password, email, created_at) values ('ssar', '1234', 'ssar@nate.com', now()); insert into user_tb(username, password, email, created_at) values ('cos', '1234', 'cos@nate.com', now()); insert into user_tb(username, password, email, created_at) values ('love', '1234', 'love@nateSELECT * FROM BOARD_TB .com', now()); insert into board_tb(title, content, created_at, user_id) values ('제목1', '내용1', now(), 1); insert into board_tb(title, content, created_at, user_id) values ('제목2', '내용2', now(), 1); insert into board_tb(title, content, created_at, user_id) values ('제목3', '내용3', now(), 2); insert into board_tb(title, content, created_at, user_id) values ('제목4', '내용4', now(), 2); insert into board_tb(title, content, created_at, user_id) values ('제목5', '내용5', now(), 2);
→ 순서대로 insert 되면 love 는 3번이됩니다. 따라서 board_tb에 love 는 존재하지 않습니다.
위 코드를 실행하면 H2 데이터베이스에 데이터가 정상적으로 삽입된 것을 확인할 수 있습니다.
notion image
notion image
 
이제 글을 insert 하기 위해서는 user_iduser 테이블의 pk 를 갖거나 null 값을 가져야합니다.
→ 즉 board 테이블의 튜플 추가를 위해 insert 쿼리와 USER_ID 선택을 위한 select 문이 추가되어야 됩니다.
 

3. 쿼리 최적화

만약 게시글을 40명이 작성했다고 가정하면 유저를 찾기 위한 select쿼리는 40번 실행되고 이는 비효율적인 쿼리입니다. 이를 해결하기 위해 FetchType.LAZY를 사용 하겠습니다.
notion image
fetch 전략을 이용하지 않으면 기본적으로 EAGER 이 적용됩니다. 이를 FetchType.LAZE 로 변경하겠습니다.
이렇게 하면 FindALL 할 때 마다 조회되던 유저 테이블을 조회하지 않고, 테이블에 저장된 1 이라는 숫자 만을 리턴하게 됩니다. 필요한 시점에만 관련 데이터를 조회하여 성능을 최적화 할 수 있는것이죠
 
결과를 테스트 코드로 확인해 보겠습니다.
notion image
notion image
첫번째 조회에서는
boardList 를 위한 board_tb 조회가 이루어 지고 있습니다. board 가 갖고 있는 userId 를 출력해도 테이블을 조회하지 않고 있어요.
(쿼리문이 더이상 출력되지 않았음)
조인된 유저 객체의 컬럼인username 을 출력하려 하자 user_tb 에서의 조회가 이루어집니다.
이는 FetchType.LAZY 전략에 의해 이루어 지며, 관련된 엔티티를 실제로 필요로 할 때 까지 데이터를 지연 로드 하는것입니다.
 
 
스프링부트 게시판 시리즈 v2 -1. https://inblog.ai/hj/27190 (User 테이블 생성 및 쿼리 수정) -2. https://inblog.ai/hj/27193 (User, Board 테이블 조인 과 JPQL) -3. https://inblog.ai/hj/27224 (회원 가입) -4. https://inblog.ai/hj/27225 DTO 를 통한 리팩토링 -5. https://inblog.ai/hj/27310 로그인, 로그아웃 -6. https://inblog.ai/hj/27316 서비스 레이어 추가 및 DTO 활용 -7. https://inblog.ai/hj/27430 예외처리 핸들러 설정과 User 서비스 리팩토링 -8. https://inblog.ai/hj/27431 Board 기능 리팩토링 -9. https://inblog.ai/hj/27560 게시글 수정, 더티체킹(flush) -10. https://inblog.ai/hj/27561 인터셉터, AOP 사용 / 마무리
 
Share article

[HootJem] 개발 기록 블로그