[스프링부트 블로그 프로젝트] 18, 20, 21강, 22강

오젼·2024년 2월 7일
0

18강 User테이블 생성

application.yml 톺아보기 ( jpa 부분 )

  jpa:
    open-in-view: true
    hibernate:
      ddl-auto: create
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
    show-sql: true
    properties:
      hibernate.format_sql: true

ddl-auto: create

!! 처음 한 번만 create로 해주고 나중에는 update로 바꿔줘야 함.
안 그럼 새로 런 할 때마다 기존에 있던 테이블 내용 날라가고(DROP) 새로 CREATE 된다.

show-sql: true

sql실행 결과 콘솔창에 보여줌

properties: hibernate.format_sql: true

원래 한 줄로 나오는데 format 맞춰서 예쁘게 보여줌

실행 후 로그 보면 ddl-auto: create로 해뒀어서 drop table if exists User 라고 나온다.

physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

Entity(table)를 만들 때 변수명 그대로 데이터베이스의 필드를 만들어준다.

default는 SpringPhysicalNamingStrategy. camel case를 snake case로 바꿔서 데이터베이스 필드를 만들어준다.

테이블 만들기

enum UserRole

package com.cos.blog.model;

public enum UserRole {
    USER, ADMIN
}

User class

package com.cos.blog.model;

import jakarta.persistence.*;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.CreationTimestamp;

import java.sql.Timestamp;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity // ORM 클래스
public class User {

    @Id // Primary key
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id; // 시퀀스: AUTO_INCREMENT

    @Column(nullable = false, length = 30)
    private String username;

    @Column(nullable = false, length = 100) // 비밀번호 암호화를 위해 넉넉하게 잡아두기
    private String password;

    @Column(nullable = false, length = 50)
    private String email;

    @Enumerated(EnumType.STRING) // EnumType.
    @ColumnDefault("'USER'")
    private UserRole role;

    @CreationTimestamp // 시간이 자동으로 입력
    private Timestamp createDate;
}

강의에선 UserRole을 그냥 string 타입으로 썼지만
원랜 enum을 쓰는 게 권장된다길래 enum 타입으로 써줬음

이 때 주의할점~ USER라는 문자를 넣어줘야 하는 것이니 작은 따옴표로 감싸주고 그 다음 큰따옴표로 감싸줘야 한다~
@ColumnDefault("USER") (X)
@ColumnDefault("'USER'") (O)

Timestamp 타입을 쓸 때도 java.security의 Timestamp가 아니라 java.sql의 Timestamp를 써줘야 한다!

Hibernate 로그 확인

MySQL Workbench에서 확인해보기

잘 만들어졌다.
와우.. jpa 정말.. 좋은 거구나...

20강 Board테이블 생성

Board class

package com.cos.blog.model;

import jakarta.persistence.*;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.CreationTimestamp;

import java.sql.Timestamp;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity // ORM 클래스
public class Board {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // AUTO_INCREMENT
    private int id;

    @Column(nullable = false, length = 100)
    private String title;

    @Lob // 대용량 데이터 large object
    @Column(columnDefinition = "longtext")
    private String content; // summernote 사용. <html>태그가 섞여서 디자인이 됨 -> 대용량

    @ColumnDefault("0")
    private int count; // 조회수

    @ManyToOne // Many=Board, User=One 한 명의 유저는 여러 개의 게시글을 쓸 수 있다.
    @JoinColumn(name="userId")
    private User user; // 작성자.
    // 원래 DB는 오브젝트를 저장할 수 없다. FK를 써야한다. 그런데 자바는 오브젝트를 저장할 수 있다.
    // ORM을 사용하면 오브젝트 코드를 DB로 매핑시킬 수 있다.

    @CreationTimestamp
    private Timestamp createDate;
}

@Lob을 썼는데도 data type이 tinycontext였음


그래서 @Column(columnDefinition = "longtext") 을 써줬다.

연관관계 매핑

  • N:1 @ManyToOne
  • 1:N @OneToMany
  • 1:1 @OneToOne
  • N:N @ManyToMany

설명 굿👍
https://jeong-pro.tistory.com/231
요약: 1:N보단 N:1을 사용, 1:1일 때 주 테이블에 외래 키를 가지도록, N:N은 사용금지

Hibernate 로그 확인

MySQL Workbench에서 확인해보기

21강 Reply 테이블 생성

어노테이션 순서 팁

@Entity가 클래스에 가장 가까이 붙어있는 게 좋다.
이 클래스가 ORM 클래스란 걸 보여주는 걸 제일 가깝게 위치시키는 게 좋기 때문에

Reply class

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity // ORM 클래스
public class Reply {

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

    @Column(nullable = false, length = 200)
    private String content;

    @ManyToOne // N:1 여러 개의 답변이 하나의 게시글에 존재할 수 있다. 답변이 N.
    @JoinColumn(name = "boardId")
    private Board board;

    @ManyToOne // N:1 여러 개의 답변을 한 명의 유저가 쓸 수 있다. 답변이 N.
    @JoinColumn(name = "userId")
    private User user;

    @CreationTimestamp
    private Timestamp createDate;
}

MySQL Workbench에서 확인해보기

키워드 정리

lombok 어노테이션

@Data : getter, setter
@NoArgsConstructor : 기본 생성자
@AllArgsConstructor : 꽉 찬 생성자
@Builder : 빌더패턴
@Entity : ORM 클래스

연관관계 매핑

@ManyToOne과 @JoinColumn이 한 쌍이라고 보면 될듯.

@JoinColumn의 name 속성으로 외래 키(Foreign Key) 컬럼의 이름을 지정한다.
생략이 가능하긴 한데 이 경우 엔티티이름_id 로 매핑이 된다.

referencedColumnName 속성으로 참조할 엔티티의 기본 키 컬럼의 이름을 지정할 수 있는데, 지정하지 않는다면 기본적으로 매핑되는 엔티티의 기본 키(ID) 컬럼이 적용된다.

외래키는 N이 되는 쪽에 있어야 함.

Timestamp는 java.sql 걸로

java.security 말고 java.sql Timestamp로
@CreationTimestamp 사용

22강 연관관계의 주인

연관관계의 주인

= FK를 누가 가지고 있는가

양방향 매핑에서는 연관관계의 주인(FK를 가지고 있는 쪽)을 정해야 한다!

테이블로 보면 단방향 관계지만, 객체 입장에서는 양방향 관계로 만들어줘야 할 때가 있다.
https://yanoo.tistory.com/121

@ManyToOne과 @JoinColumn

N:1 쪽에서 N이 FK를 가지고 있어야 한다.
@ManyToOne과 @JoinColumn을 한 쌍으로 써준다고 보면 된다.

보통

@ManyToOne
@JoinColumn(name = "")

식으로 써주는데

@JoinColumn의 name속성은 단지 FK의 이름을 생성해주는 역할이다.

그렇다면 연관관계는 어떻게 이루어지는 것인가? 하면
referencedColumnName 속성으로 FK가 조인할 대상의 컬럼명을 설정해줘야 한다.
그런데 이를 생략하면 해당 테이블의 PK가 자동으로 할당된다.
👍https://www.inflearn.com/questions/113969/comment/85022

또한 name 속성도 생략할 수 있는데, 이 경우 엔티티명_id로 이름이 자동생성된다.

@OneToMany와 mappedBy

이 때 1 쪽에선 FK가 필요하지 않다.

그래서 @OneToMany를 해주고 mappedBy 속성을 사용해줘야 한다.

자신은 FK가 아니며 DB에 컬럼을 만들지 말라고 알려주는 것!

mappedBy 다음엔 연결될 엔티티의 변수명을 적어준다!

@OneToMany(mappedBy = "")

FetchType

@ManyToOne은 기본 FetchType이 FetchType.EAGER 즉시로딩!
@OneToMany는 기본 FetchType이 FetchType.LAZY 지연로딩!

Board 테이블 수정

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity // ORM 클래스
public class Board {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // AUTO_INCREMENT
    private int id;

    @Column(nullable = false, length = 100)
    private String title;

    @Lob // 대용량 데이터 large object
    @Column(columnDefinition = "longtext")
    private String content; // summernote 사용. <html>태그가 섞여서 디자인이 됨 -> 대용량

    @ColumnDefault("0")
    private int count; // 조회수

    @ManyToOne // Many=Board, User=One 한 명의 유저는 여러 개의 게시글을 쓸 수 있다.
    @JoinColumn(name="userId")
    private User user; // 작성자.
    // 원래 DB는 오브젝트를 저장할 수 없다. FK를 써야한다. 그런데 자바는 오브젝트를 저장할 수 있다.
    // ORM을 사용하면 오브젝트 코드를 DB로 매핑시킬 수 있다.

    @OneToMany(mappedBy = "board", fetch = FetchType.EAGER) // mappedBy 연관관계의 주인이 아니다. (난 FK가 아니에요. DB에 컬럼을 만들지 마세요)
    private List<Reply> reply;

    @CreationTimestamp
    private Timestamp createDate;
}

0개의 댓글