세개의 테이블 생성을 위한 model 패키지 만들기 (com.cos.blog.model)
Blog 테이블은 User, Board, Reply 를 만들것이다
1. User 테이블 만들기
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder // 빌더 패턴!!
//ORM -> Java(다른언어) Object -> 테이블로 매핑해주는 기술
@Entity // User 클래스가 MySQL에 테이블이 생성이 된다.
// @DynamicInsert // insert시에 null인 필드를 제외시켜준다.
public class User {
@Id //Primary key
@GeneratedValue(strategy = GenerationType.IDENTITY) // MySQL이라서 auto_increment 사용
private int id; // 시퀀스, auto_increment
@Column(nullable = false, length = 100, unique = true)
private String username; // 아이디
@Column(nullable = false, length = 100) // 123456 => 해쉬 (비밀번호 암호화)
private String password;
@Column(nullable = false, length = 50)
private String email; // myEmail, my_email
// @ColumnDefault("user") 회원가입 할때 기본값은 user
// DB는 RoleType이라는 게 없다.
@Enumerated(EnumType.STRING)
private RoleType role; // Enum을 쓰는게 좋다. // ADMIN, USER
private String oauth; // kakao, google
// 내가 직접 시간을 넣으려면 Timestamp.valueOf(LocalDateTime.now())
@CreationTimestamp
private Timestamp createDate;
}
- 어노테이션 설명
@Entity : User 클래스가 MySQL에 테이블이 자동 생성이 된다.
☆ DB에 매핑시켜주는 어노테이션은 클래스와 젤 가까이 두는게 좋다.
@GeneratedValue(strategy = GenerationType.IDENTITY) : 프로젝트에 연결 된 DB의 넘버링 전략을 따라간다.
이 말은 즉슨 오라클을 사용하면 시퀀스를 사용하고, MySQL을 사용하면 auto_increment 를 사용한다. (자동 입력)
** yml의 이 부분이 jpa의 기본 넘버링 전략을 따라가지 않겠다 = false를 설정해놓는다.
jpa:
use-new-id-generate-mappings : false
@Column(nullable = false, length = 100, unique = true) : null이 될 수 없다 / 길이는 100자 /
@CreationTimestamp : 시간이 자동 입력이 된다.
@Enumerated(EnumType.STRING)
private RoleType role
role 데이터 타입을 Enum 을 쓰면 좋은게 admin, user 둘 중에 쓸 수 있도록 도메인 설정을 할 수 있다.
도메인이란? 범위가 정해지는것. 예를들어 성별이라면 남/녀 , 학년이라면 1/2/3/4/5/6 학년
스프링 실행하기 전에 application.yml 에서 create인지 확인한다.
create 는 프로젝트 실행할때마다 테이블을 새로 만든다는 것. 최초에만 create 그뒤로는 update 로 수정해야함.
jpa:
open-in-view: true
hibernate:
ddl-auto: create
[application.yml]
show-sql: true
이 있기때문에 콘솔창에
create table User (
id integer not null auto_increment,
createDate datetime(6),
email varchar(50) not null,
passsword varchar(100) not null,
role varchar(255) default 'user',
username varchar(30) not null,
primary key (id)
) engine=InnoDB
뜬다.
원래는 한줄로 보이는데
hibernate.format_sql: true
이것때문에 보기좋게 정렬돼서 나옴.
PhysicalNamingStrategyStandardImpl 은 @Entity 를 만들때 즉 테이블을 만들때 변수명 그대로 DB에 사용한다.
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
만약 변수명을 수정하고 저장만 하면 쿼리가 다시 재수정 된다. 이것을 ORM 이라고 한다.
( 예를들어 User클래스의 email 변수명을 myEmail 로 바꾸면 MySQL에 자동으로 바꿔줌. )
ORM 이란?
Java (혹은그 외 다른언어도 포함)를 Object(객체)를 테이블로 매핑해주는 기술
2. Board 테이블 만들기
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // auto_increment
private int id;
@Column(nullable = false, length = 100)
private String title;
@Lob // 대용량 데이터
private String content; // 섬머노트 라이브러리 <html>태그가 섞여서 디자인이 됨.
private int count; // 조회수
@ManyToOne(fetch = FetchType.EAGER) // Many = Board, User = One
@JoinColumn(name="userId")
private User user; // DB는 오브젝트를 저장할 수 없다. FK, 자바는 오브젝트를 저장할 수 있다.
@OneToMany(mappedBy = "board", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE) // mappedBy 연관관계의 주인이 아니다 (난 FK가 아니에요) DB에 칼럼을 만들지 마세요.
@JsonIgnoreProperties({"board"})
@OrderBy("id desc")
private List<Reply> replys;
@CreationTimestamp
private LocalDateTime createDate;
}
DB는 객체저장을 못해서 원래는 private int userId 로 해서 FK값으로 저장한다
하지만 jpa 를 사용하면 객체를 저장할 수 있다.
@ManyToOne(fetch = FetchType.EAGER) // Many = Board, User = One
@JoinColumn(name="userId")
private User user;
User객체를 테이블에서는 fk로 인식을 하고
@JoinColumn(name="userId") : userId 이름으로 테이블 필드값이 저장된다.
user객체와 연관관계 설정
@ManyToOne(fetch = FetchType.EAGER) :
다수의 게시물과 하나의 유저 (한명의 유저는 여러개 게시글을 쓸 수 있다.)
fetch = FetchType.EAGER 한명의 유저 정보는 무조건 가져온다.
패치 전략 2가지 (EAGER / LAZY)
- -EAGER
게시글 상세보기 페이지에 작성자가 바로 보여야할때 username 을 무조건 들고와야한다 = EAGER전략
* @ManyToOne만 있으면 무조건 들고오는것
게시글에는 유저가 하나밖에 없음 무조건 바로 가져오겠다는 뜻
- LAZY
게시글에 댓글은 여러개니까 필요하면 들고오고 불필요하면 안들고오겠다.
예를들어 게시글에서 댓글 펼치기 기능이있다면 펼치기 버튼 누르기 전엔 댓글이 바로 보여지지 않기 때문에
무조건 들고와야하는건 아니다. = LAZY전략
@OneToMany(mappedBy = "board",fetch = FetchType.LAZY)
private List<Reply> reply;
@OneToMany(mappedBy = "board", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
@JsonIgnoreProperties({"board"})
@OrderBy("id desc")
private List<Reply> replys;
List<Reply> : 하나의 게시글에는 여러개의 댓글이라서 List
@JoinColumn(name="replyId") 가 필요가 없다
왜? DB에 replyId 필드가 생기게 되면 여러 댓글이 달렸을 경우 한 필드에 여러 값을 넣을 수 없어서 원자성에 방해됨
DB에서 하나의 컬럼은 원자성(하나의 값)을 가진다. = 1정규화
@OneToMany(mappedBy = "board", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
mappedBy = "board" 는 reply 클래스의 Board board 이름.
Reply 테이블에 있는 board가 FK이고 Board테이블에 있는 reply는 FK가 아니다.
즉 mappedBy 연관관계의 주인이 아니니 DB에 칼럼을 만들지 않는다.
- Reply 테이블
id | content | userId | boardId |
1 | 좋아요 | 2 | 1 |
2 | 연락주세요! | 3 | 1 |
Reply 테이블에 있는 board가 FK
- Board 테이블
id | title | content | userId | createDate |
1 | 스터디 구합니다 | 블로그 플젝.. | 1 | 2021.5.27 |
프로그램 실행하면 테이블 자동 생성.
* longtext 대용량 데이터
객체 user를 DB는 객체를 저장할 수 없기때문에 int값으로 만들어졌고
userId 이름으로 테이블 필드값이 저장된 것을 볼수 있다 userId integer
연관관계를 설정했기 때문에 board테이블에 userid컬럼은 user테이블의 id를 참조하는 것을 자동으로 제약조건이 생성된 것을 볼 수 있다.
3. reply 테이블 만들기
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class Reply {
@Id //Primary key
@GeneratedValue(strategy = GenerationType.IDENTITY) // 시퀀스, auto_increment
private int id;
@Column(nullable = false, length = 200)
private String content;
@ManyToOne
@JoinColumn(name="boardId")
private Board board;
@ManyToOne
@JoinColumn(name="userId")
private User user;
@CreationTimestamp
private LocalDateTime createDate;
@Override
public String toString() {
return "Reply [id=" + id + ", content=" + content + ", board=" + board + ", user=" + user + ", createDate="
+ createDate + "]";
}
}
어느 게시물의 댓글인지 알기 위해서 연관관계가 필요
@ManyToOne
@JoinColumn(name="boardId")
private Board board;
위처럼 Board 객체를 테이블에서는 fk로 인식을 하고
@JoinColumn(name="boardId") 열이름만 정했고 어디와 연관관계인지 모른다.
연관관계는 @ManyToOne = 여러개의 답변 to 하나의 게시글
* @OneToMany 은 하나의 답변 to 여러개의 게시글 (X)
어느 유저의 댓글인지도 알아야한다.
@ManyToOne // 여러개의 답변들에 하나의 유저
@JoinColumn(name="userId")
private User user;
reply테이블의 boardId는 board 테이블의 id를 참조하고 있다. userId도 같음.
Board 클래스에는 User객체가 있어서 board만 select했는데 user정보도 함께 들고온다.
'Spring boot | 블로그 만들기' 카테고리의 다른 글
회원삭제 테스트 | Exception 처리 (0) | 2022.11.05 |
---|---|
회원수정 테스트 | save()와 @Transactional 더티체킹 (1) | 2022.11.05 |
회원가입 테스트 | insert , Enum 사용법 (1) | 2022.11.04 |
MySQL 설정, DB와 프로젝트 연결 (1) | 2022.10.31 |
패키지 생성법, 의존성 설정, 제어의 역전(Ioc)이란 (0) | 2022.10.31 |