JAVA Spring boot) 소비기록앱 소비일기 서버(Backend) 개발일지 2 - DB 테이블 설계와 생성(with JPA)
- 작성일 : 2022.08.25
-
작성자 : 황시아
- 팀원 : 박승지, 오성은, 황시아
- GitHub Repository : https://github.com/miro7923/soil
개발환경
- MacBook Air (M1, 2020)
- OpenJDK 11
- IntelliJ IDEA Community Edition
- Spring Boot 2.7.3(예정)
- MySQL Workbench 8.0.28
기간
- 2022.8.15 ~
주제
- 오늘의 소비에 대한 기억과 감정을 기록으로 남기고 나중에 되돌아보는 시간이 있었으면 좋겠다는 생각에 진행하게 된 프로젝트이다.
- 새로 산 물건의 사진을 찍고 그에 대한 감상을 함께 글로 남길 수 있는 기능을 메인으로 제작할 것이다.
진행상황
- 앱에 필요한 데이터베이스 테이블을 설계하고 생성했다.
- DB 테이블의 생성에는
JPA
를 사용했다.
도메인 모델과 테이블 설계
- 모든 진행은 실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 강의를 기반으로 했다.
- 강의의 흐름대로 먼저 대략적인 엔티티들의 관계를 설정했다.
- 소비일기에는 총 5개의 테이블이 존재한다.
- 한 명의 회원은 여러 개의 일기와 게시글, 댓글을 작성할 수 있고 여러 개의 카테고리를 만들 수 있기 때문에 나머지 4개의 테이블과의 관계를
일대다
로 설정했다. - 하나의 카테고리는 여러 개의 일기에 사용될 수 있기 때문에 둘의 관계는
일대다
로 설정했다. - 하나의 게시글에 여러 개의 댓글이 작성될 수 있기 때문에 둘의 관계는
일대다
로 설정했다.
- 위에서 설정한 관계를 바탕으로 다이어그램을 만들었다.
- 굵게 표시한 텍스트는 외래키이다.
- 최종 정리!
엔티티 클래스 생성
- 엔티티 클래스를 생성한 뒤
JPA
로 매핑을 해 주었다.
Member
@Entity
@Getter
public class Member {
@Id @GeneratedValue
@Column(name = "member_id")
private Long id;
@Column(nullable = false)
private String name;
private String password;
}
Diary
@Entity
@Getter
public class Diary {
@Id @GeneratedValue
@Column(name = "diary_id")
private Long id;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "member_id", nullable = false)
private Member member;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "category_id", nullable = false)
private Category category;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String content;
@Column(nullable = false)
private LocalDateTime date;
private String photo;
private int price;
}
Category
@Entity
@Getter
public class Category {
@Id @GeneratedValue
@Column(name = "category_id")
private Long id;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "member_id", nullable = false)
private Member member;
@Column(nullable = false)
private String name;
}
Board
@Entity
@Getter
public class Board {
@Id @GeneratedValue
@Column(name = "board_id")
private Long id;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "member_id", nullable = false)
private Member member;
@Column(nullable = false)
private String content;
@Column(nullable = false)
private LocalDateTime date;
private int readcount;
}
Comment
@Entity
@Getter
public class Comment {
@Id @GeneratedValue
@Column(name = "comment_id")
private Long id;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "member_id", nullable = false)
private Member member;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "board_id", nullable = false)
private Board board;
@Column(nullable = false)
private String content;
private LocalDateTime date;
}
- 각 테이블의
ID
컬럼명을 지정해 주고 외래 키도 매핑해 주었다. - 엔티티 설계 시
Setter
를 통한 무분별한 데이터 변경 방지를 위해Getter
만 사용했다. - 모든 연관관계는 지연로딩으로 설정하는 것이 원칙이기 때문에
@ManyToOne
어노테이션에LAZY
속성값을 설정해 주었다. 왜냐면XToOne
어노테이션들은 기본값이EAGER
라서 즉시로딩이기 때문이다. 모든 연관관계를 지연로딩으로 설정해야 하는 이유는 즉시로딩은 예측이 어렵고 실행된 SQL을 추적하는 것이 어렵다. 그리고JPQL
실행 시N+1
문제가 자주 발생하기 때문에 즉시로딩은 지양하는 것이 좋다. 데이터 하나만 조회하려 했는데 여러 컬럼 각각을 대상으로 SQL이 실행 돼면서 같은 데이터가 여러 개가 쏟아지는 상황이 발생하는 것이다. jpa-hibernate-ddl-auto
는update
로 설정했다.- 이렇게 설정한 후 어플리케이션을 실행하니까 테이블 생성 쿼리가 실행되면서 외래 키도 모두 설정해 주고
Null
을 허용하지 않은 컬럼에는 그것도 다 설정해 주고… 정말 편했다. 테이블 설정값을 바꾸고 새로 생성하고 싶으면create
옵션으로 설정하고 어플리케이션을 재실행하면 테이블 드롭 후 재생성되고… 너무너무 편했다. 😳 예전에 워크벤치에서 하나하나 생성하던 시절엔 참 힘들었다. 학원에선 왜 그렇게 노가다를 시켰을까…