본문 바로가기

Spring

(mac) [GDSC] Spring 스터디 2주차 - ERD설계 및 JPA를 활용한 데이터생성

2주차 스터디는 게시판, 댓글의 ERD를 설계하고 Spring에서 구현 후 JPA를 이용해 데이터 생성 및 ERD를 띄우는 겁니다.

 

일단 저는 게시판, 댓글의 ERD를 draw.io 에서 설계하다 user라는 테이블이 있으면 더 좋겠다고 생각이 들어 user또한 추가적으로 만들어보았습니다.

     - 추후에 문제가 되면 수정하면 되니까..

 

사실 ERD설계는 학교 데이터베이스 수업때 제외하고 거의 한 적이 없어 가물가물했습니다...

아마도 어딘가 틀린 내용이 있을 것 같은 느낌..?

ERD설계 할 때마다 느끼는건데 머리가 아주 어질어질하다는점ㅋㅋ


ERD

 

ERD입니다.

 

첫번째로 user(사용자) 테이블입니다.

 

기본키 필드는 userId이며 타입은 Long, sql의 auto-increment를 사용할 예정입니다.

추가로 비밀번호 필드는 password 타입은 String입니다.

 

두번째로 comment(댓글) 테이블입니다.

 

기본키는 commentId이며 타입은 Long, userId와 똑같이 sql의 auto-increment를 사용할 예정입니다.

댓글의 외래키는 userId, postId입니다.

하나의 사용자는 여러개의 댓글을 등록할 수 있다. (1:N)

하나의 게시물에는 여러개의 댓글이 달릴 수 있다. (1:N)

이렇게 생각하여 이렇게 연관관계를 설정했습니다.

 

추가로 댓글의 내용 comment, 생성일시 createAt, 수정일시 modfiedAt 칼럼(필드)이 있습니다.

 

마지막으로 post(게시물) 입니다.

 

기본키는 postId이며 타입은 Long, userId와 똑같이 sql의 auto-increment를 사용할 예정입니다.

외래키는 userId입니다.

하나의 사용자는 여러개의 게시물을 등록할 수 있다. (1:N)

이렇게 생각하여 연관관계를 설정했슴다.

 

추가로 게시물 내용인 content, 생성일시 createAt, 수정일시 modfiedAt 칼럼(필드)이 있습니다.

 


 

Spring 내부에서 Entity 설계

 

User 클래스

package com.study.study.entity;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Getter
@Table(name = "user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long userId;

    @Column(name = "password")
    private String password;
}

 

 

Post 클래스

package com.study.study.entity;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.LastModifiedDate;

import java.util.List;

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Getter
@Table(name = "post")
public class Post {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long postId;

    @Column(columnDefinition = "TEXT", nullable = false)
    private String content;

    @Column(name = "modifiedAt")
    @LastModifiedDate
    private String modifiedAt;

    @ManyToOne
    @JoinColumn(name = "userId")
    private User user;

    @OneToMany(mappedBy = "post")
    private List<Comment> comments;





}

 

Comment 클래스

package com.study.study.entity;

import jakarta.persistence.*;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;

@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Table(name = "comment")
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long commentId;

    @Column(columnDefinition = "TEXT", nullable = false)
    private String comment;

    @Column(name = "createAt")
    @CreatedDate
    private String createAt;

    @Column(name = "modifiedAt")
    @LastModifiedDate
    private String modifiedAt;

    @ManyToOne
    @JoinColumn(name = "postId")
    private Post post;


    @ManyToOne
    @JoinColumn(name = "userId")
    private User user;
}

 

어노테이션 설명

 

@Entity

Entity 어노테이션은 DB의 테이블과 1:1로 매핑된다고 합니다.

즉, Entity 객체의 인스턴스 하나가 테이블에서 하나의 레코드 값이라고 할 수 있습니다.

 

속성으로 name이 있으며 JPA에서 사용할 엔티티의 이름을 지정합니다.

설정하지 않을 경우 클래스의 이름을 사용합니다.

 

추가로 JPA는 엔티티 객체를 생성할 때 기본 생성자를 사용하기 때문에 기본 생성자는 필수입니다.

 

@Table

엔티티와 매핑할 테이블을 지정합니다.

 

속성

name - 매핑할 테이블의 이름을 지정합니다. 설정하지 않으면 클래스의 이름을 사용합니다.

catalog - catalog 기능이 있는 데이터베이스에서 catalog를 매핑합니다.

schema - 스키마 기능이 있는 데이터베이스에서 스키마를 매핑합니다.

 

@Id

클래스 필드에 선언하며 해당 필드는 해당 Entity의 기본키(Primary Key) 가 될 것임을 지정합니다.

 

 

@GeneratedValue - 기본 키 자동생성 전략 

대리키를 사용하는 전략입니다.

 

속성

strategy - 생성 전략을 설정해주기 위해 사용합니다.

- 생성 전략의 종류

IDENTITY - 생성 전략을 DB에게 위임합니다. 즉, DB의 기본키 생성 전략을 따라갑니다.

SEQUENCE - DB의 특별한 오브젝트 시퀸스를 사용하여 기본키를 생성합니다.

TABLE - DB에 키 생성 전용 테이블을 만들고, 이것을 사용해 기본키를 생성합니다.

AUTO - JPA구현체가 자동으로 생성전략을 결정합니다.

 

@Column

객체의 필드를 테이블의 컬럼에 매핑합니다.

 

속성

name - 필드와 매핑시킬 컬럼의 이름을 지정합니다

nullable - null값의 사용여부를 결정합니다. false면 NOT NULL 제약조건이 추가됩니다.

 

 

@ManyToOne(N:1)

Post클래스는 userId를 외래키를 갖고있는 연관관계의 주인입니다.

post입장에서 user 하나는 다수의 post를 작성할 수 있습니다

즉, post(N) : user (1) 로 판단을 하여 ManyToOne을 사용했습니다 (외래키는 userId로 지정)

 

Comment클래스는 postId, userId를 외래키를 갖고있는 연관관계의 주인입니다.

commnet입장에서 post(게시물)하나에 다수의 comment를 작성할 수 있습니다.

즉, comment(N) : post(1) 로 판단하여 ManyToOne을 사용했습니다.

comment입장에서 user 하나는 다수의 comment를 작성할 수 있습니다.

즉, comment(N) : user(1) 로 판단하여 ManyToOne을 사용했습니다.

 

@OneToMany

이 어노테이션을 잘 사용했는지는 모르겠습니다.

사용한 클래스는 Post클래스입니다.

 

왜 사용하자는 판단을 했느냐?

 

OneToMany 즉, 일대다 관계(1:N)..

게시물 입장에서는 하나의 게시물에 많은 댓글이 달릴 수 있습니다.

즉 post(1) : comment(N) 이 아닌가? 싶지 않아 이런 연관관계를 설정했어요!..

 

++

추가적으로

@AllArgsConstructor
@NoArgsConstructor
@Builder
@Getter

 

이 어노테이션들은 LomBok 플러그인이 지원하는 어노테이션입니다.

JPA를 이용해 엔티티를 설계할 때 생성자 및 접근자, 빌더패턴을 사용해야 된다~ 라고 어느 블로그에서 봤습니다.

그렇기 때문에 사용한 어노테이션입니다.

 


데이터 바인딩 및 ERD를 띄워보자

 

 

엔티티 설정을 모두 마친 후 서버를 실행시킵니다.

 

콘솔 로그에 JPA hibernate가 쿼리문을 짜쭈는걸 확인 가능합니다.

 

그리고 DataGrip에 들어가 확인해봅시다

 

 

테이블이 생성된걸 확인 가능

+ 외래키 기본키도 생성이 됐다.

++ 근데 post의 댓글 객체는 생성이 안됐네 칼럼을 지정 안해줘서 그런가?..

 


ERD를 띄워보자

 

 

 

이렇게 하단에 Persistence가 있습니다.

 

main 내부에 entityManagerFactory가 있습니다.

 

 

우클릭 후 Entity Relationship Diagram 클릭

 

 

 

이렇게 인텔리제이 내부에서 ERD를 확인할 수 있습니다~

 

뭐 잘 짠건지는 잘 모르겠지만 에러 안나고 잘 된거에 다행이라고 여기자^^

 


 

+ 추가 application.yml 세팅

 

이렇게 JPA를 통해 엔티티를 설계하고 DB와 바인딩을 하려면 세팅을 먼저 해줘야 합니다.

 

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:<포트넘버>/<DB명>?useSSL=false&serverTimezone=Asia/Seoul&characterEncoding=UTF-8
    username: <사용자이름>
    password: <비밀번호>


  jpa:
    open-in-view: true
    hibernate:
      ddl-auto: create
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
      use-new-id-generator-mappings: false
    show-sql: true
    properties:
      hibernate.format_sql: true
      dialect: org.hibernate.dialect.MySQL8InnoDBDialect


logging:
  level:
    org.hibernate.SQL: debug

 

 

DB설정 뿐 만이 아닌 jpa에 관련된 설정도 해줘야 합니다!