Java/Spring boot 프로젝트

Spring Boot JPA 설정, 테이블 생성(Entity) - 게시판 만들기(3)

seungh1024 2023. 2. 19. 10:26
728x90

의존성 추가 - build.gradle(api 모듈)

dependencies {
    runtimeOnly 'mysql:mysql-connector-java' //MySQL
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa' //JPA
}

다음과 같이 JPA 의존성을 추가해 준다.

위와 같이 의존성을 추가해주면 테이블 생성, 쿼리문 등을 매우 간편하게 할 수 있는 어노테이션이나 메소드들을 사용할 수 있게된다.

implementation

implemetation은 해당 라이브러리가 변경되더라도 이 라이브러리와 연관된 모든 모듈들을 컴파일하지 않고 직접 관련이 있는 모듈들만 컴파일하기 때문에 rebuild 속도가 빠르다.

 

혹시 JPA에 대해 잘 모른다면 아래 링크에 간단하게 설명한 것이 있다.

JPA와 ORM 간단히 알아보기

 

 

JPA 설정

application.yml(member-api 모듈)

server:
  port: 8080

spring:
  #MySQL
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: ${mysql.url}
    username: ${mysql.username}
    password: ${mysql.password}

  #JPA
  jpa:
    #database-platform: org.hibernate.dialect.MySQL8Dialect
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        format_sql: true
        show_sql: true
        highlight_sql: true
    defer-datasource-initialization: true
  • spring.jpa.database.platform
    • 데이터베이스 엔진 종류를 설정한다.
    • dialect 설정은 데이터베이스 유형을 지정하도록 하는 것으로 Spring Boot 실행 시에 아래와 같이 연결된 DB에 자동으로 지정이 되므로 특별한 이유가 없다면 수동으로 설정할 필요가 없다.

  • spring.jpa.hibernate.ddl-auto
    • 엔티티를 기준으로 테이블을 생성하는 규칙을 정의한다. 아래는 옵션들이다.
    • none → 엔티티가 변경되더라도 데이터베이스를 변경하지 않는다.
    • update → 엔티티의 변경된 부분만 적용한다.
    • validate → 변경사항이 있는지 검사만 한다.
    • create → 스프링부트 서버가 시작될 때 모두 drop하고 다시 생성한다.
    • create-drop → create와 동일하지만 서버가 종료될 때에도 모두 drop한다.
    • 개발 환경에서는 update를 많이 사용하고 실제 운영할 땐 none, validate를 많이 사용한다고 한다.
  • spring.jpa.properties.hibernate
    • format_sql : DB가 수행하는 모든 쿼리문을 콘솔에 출력하는 설정. default 값은 false로 true면 콘솔에 출력함
    • show_sql : 콘솔, 로그의 SQL을 예쁘게 출력한다. format_sql의 옵션을 설정하지 않는다면 출력하지 않으니 그땐 필요없는 설정이다. 마찬가지로 default 값은 false, true면 적용된다.
    • highlight_sql : SQL출력을 ANSI secape codes를 사용하여 색을 넣어준다.(사용해보니 가독성이 더 좋아지더라)
  • defer-datasource-initialization : db 시작할 때 기본으로 넣어주고 싶은 값들을 쿼리로 실행하고 싶을 때 data.sql 파일을 작성하여 실행한다. 이때 data.sql이 Hibernate 초기화되기 전에 실행되기 때문에 설정하는 옵션이다. Hibernate 초기화를 통해 생성된 스키마에다 데이터를 채우기 위해 data.sql이 실행되기를 원한다면 이 옵션을 true로 설정해줘야 한다.

Entity

Entity란?

데이터베이스 테이블과 매핑되는 자바 클래스를 의미한다.

사용자관련 API를 먼저 만들기 위해 사용자 엔티티 클래스가 필요하다.

우선 속성으로는 id, email, password, name 정도만 생각해서 만들어보겠다.

여기서 id는 pk, email은 로그인시 아이디로 만들었다.

클래스 이름은 Member로, entity라는 패키지를 생성하여 만들었다.

 

entity/Member(member-api 모듈)

package com.seungh1024.api.entity;

import jakarta.persistence.*;
import lombok.*;

@Entity
@Table(name = "member")
@Getter
@ToString(exclude = "memberPassword")
@NoArgsConstructor
public class Member {
    @Id
    @Column(name = "member_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int memberId;

    @Column(name = "member_email", unique = true)
    private String memberEmail;

    @Column(name = "member_password")
    private String memberPassword;

    @Column(name = "member_name")
    private String memberName;

    @Builder
    public Member(int memberId, String memberEmail, String memberPassword, String memberName){
        this.memberId = memberId;
        this.memberEmail = memberEmail;
        this.memberPassword = memberPassword;
        this.memberName = memberName;
    }
}
💡 Spring Boot 2.x 버전을 사용하는 경우 jakarta가 아닌 javax를 import 해줘야한다.

 

@Entity

  • 해당 어노테이션이 적용된 클래스는 JPA가 엔티티로 인식하며 테이블과 링크될 클래스임을 나타낸다.
  • 기본값으로 클래스의 카멜케이스 이름을 언더 스코어 네이밍(_)으로 테이블 이름을 매핑한다.
  • Ex) SalesManager.java → sales_manager table

@Getter

  • getter 메서드를 자동으로 생성하기 위해 롬복의 @Getter 어노테이션을 적용했다. 코드에는 없지만 작성한 것과 동일한 효과를 가진다.

@Table

  • @Entity에서 기본적으로 생성해주는 테이블 이름을 직접 지정할 수 있다.
  • name 속성을 사용하여 매핑할 테이블 이름을 정할 수 있다.

@toString

  • toString() 메소드를 자동으로 생성해준다.
  • exclude 속성으로 특정 필드를 toString() 결과에서 제외시킬 수 있다.

@NoArgsConstructor

  • 아무런 매개변수가 없는 생성자를 자동으로 만들어준다.

@AllArgsConstructor

  • 여기에는 없지만 위의 어노테이션과 같은 성격으로 모든 필드에 대한 생성자를 자동으로 만들어준다.

@RequiredArgsConstructor

  • 여기에는 없지만 위의 어노테이션과 같은 성격으로 required된 필드에 대한 생성자를 자동으로 만들어준다. 즉 초기화되지 않은 final로 선언된 필드들나 @NonNull이 붙은 필드와 같이 반드시 값이 할당되어야 하는 그런 필드들에 대한 생성자를 만들어주는 것이다.

@Id

  • @Id 어노테이션은 해당 속성을 pk로 지정한다. pk로 지정했기 때문에 해당 속성의 값은 DB에 동일한 값으로 저장될 수 없다.

@Column

  • 테이블의 컬럼을 나타내며 굳이 선언하지 않아도 해당 클래스의 필드는 모두 컬럼이 된다.
  • 엔티티 객체 속성을 테이블 컬럼에 매핑한다
  • 이 어노테이션을 생략하면 memberId의 경우 member_id로 DB에 저장된다. camelCase가 소문자로 변경되고 언더바로 단어가 구분되어 저장된다. 아래 속성 중 name을 지정하지 않아도 마찬가지이다.
  • 자주 사용하는 속성
    • name → 필드와 매핑할 테이블 컬럼 이름 지정
    • unique → 테이블의 컬럼에 unique 제약조건을 적용한다.
    • length → 문자 길이 제약조건으로 String 타입에만 사용하며 기본값은 255이다.
    • nullable → null값의 허용 여부를 설정하며 false 옵션을 줄 경우 not null, 기본값은 true로 되어있다.
    • columnDefinition=”TEXT” → 글자 수를 제한할 수 없는 경우에 사용한다.

@GeneratedValue

  • PK 생성 규칙
  • 위와 같이 strategy = GererationType.IDENTITY 옵션을 주면 해당 속성에 값을 따로 설정하지 않아도 1씩 자동으로 증가하며 저장된다. 테이블에서 auto increment 속성과 같다.

@Builder

  • 해당 클래스의 빌더 패턴 클래스를 생성한다.
  • 생성자 상단에 선언 시 생성자에 포함된 필드만 빌더에 포함한다.

생성자의 경우, 생성자를 많이 만들어야 한다면 코드 가독성이 떨어지며 인자가 추가되는 경우 코드를 수정하기 어렵다.또한 각 인자가 어떤 의미인지 인자가 많다면 헷갈리고 잘못 넣는 경우도 발생한다.

하지만 Builder패턴을 적용한다면 각 인자가 어떤 의미인지 알기 쉽고 잘못된 값을 넣었는지 쉽게 알 수 있다.

사용법은 나중에 보여주겠다.

@Setter

여기엔 setter메소드가 보이지 않는다. 자바빈 규약을 생각하며 getter/setter를 무작정 생성하는 경우 클래스의 인스턴스 값들이 언제 변경되는지 명확하게 알 수 없다.

  • Entity 클래스에서는 setter 메소드를 만들지 않도록 노력한다.
    • 무조건 쓰지 말아야 하는 것은 아니지만 이 setter에 의한 문제가 발생할 여지를 남겨두는 것이 좋지 않다.
    • 이게 시스템이 복잡하면 여기 저기서 setter를 호출하고 update문이 어디서 누구에 의해 발생했는지 추적하기가 매우 어려워진다고 한다.
  • setter 메소드가 아닌 생성자를 이용해서 초기화 하는 경우 불변 객체로 활용할 수 있고 불변 객체로 만들면 데이터를 전달하는 과정에서 변조되지 않음을 보장할 수 있다.

결과 확인

우선 서버 실행 전에 해당 데이터베이스에 테이블이 있는지 확인해보면 아래와 같다.

 

하지만 재 실행후 로그를 보면

이렇게 설정했던 것 처럼 테이블 작성 쿼리를 볼 수 있다.

여기 쿼리문 실행된 것을 보면 들여쓰기가 잘 되어있는데 아까 설정에서 show_sql 설정이고

색깔이 들어가서 가독성이 좋은 것인 highligt_sql 옵션이 잘 적용된 것이다

 

DB에 접속해서 확인해보면 내가 작성한 entity처럼 잘 생성된 것을 볼 수 있다.

 

 

728x90