세개의 테이블 생성을 위한 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정보도 함께 들고온다.

 

반응형
LIST

+ Recent posts