Day 3

Day3

์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ JPA๋กœ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค๋ฅผ ๋‹ค๋ฃจ๊ธฐ

๐Ÿ‘‰JPA์˜ ๋“ฑ์žฅ ๋ฐฐ๊ฒฝ

JPA๋ผ๋Š” ์ž๋ฐ” ํ‘œ์ค€ ORM(Object Relational Mapping)๊ธฐ์ˆ 

๊ฐ์ฒด๋ฅผ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ

๋‹จ์ˆœ SQL๋ฌธ์„ ์‚ฌ์šฉํžˆ ๋ฌธ์ œ

  • SQL๋ฌธ์€ ๋‹จ์ˆœํ•œ ๋ฐ˜๋ณต ์ž‘์—…์ด ๋˜๊ณ  , ์ด๋Š” ํ”ผํ•  ์ˆ˜ ์—†๋‹ค

  • ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜

    • ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ์–ด๋–ป๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ• ์ง€์— ์ดˆ์ฒจ์ด ๋งž์ถฐ์ง„๊ธฐ์ˆ 

    • ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋Š” ๋ฉ”์„ธ์ง€๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐ€๋Šฅ๊ณผ ์†์„ฑ์„ ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ์ˆ 

    • ๊ฐ์ฒด๋ฅผ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•˜๋ ค๊ณ  ํ•˜๋‹ˆ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ์ด๋ฅผ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜๋ผ๊ณ  ํ•จ

JPA๋Š” ์ค‘๊ฐ„์—์„œ ํŒจ๋Ÿฌ๋‹ค์ž„์„ ์ผ์น˜์‹œ์ผœ์ฃผ๊ธฐ ์œ„ํ•œ ๊ธฐ์ˆ 

= ๊ฐœ๋ฐœ์ž๋Š” ๊ฐ์ฒด์ง€ํ–ฅ์ ์œผ๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๊ณ , SQL์— ์ข…์†์ ์ธ ๊ฐœ๋ฐœ์„ ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค

๐Ÿ‘‰Spring Data JPA๋ž€?

JPA๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ์„œ ์ž๋ฐ” ํ‘œ์ค€ ๋ช…์„ธ์„œ์ด๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค์ด๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ตฌํ˜„์ฒด๊ฐ€ ํ•„์š”ํ•จ( ex - Hibernate, Eclipse ๋“ฑ) โ‡’ ํ•˜์ง€๋งŒ Spring์—์„œ JPA๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์ด ๊ตฌํ˜„์ฒด๋ฅผ ์ง์ ‘ ๋‹ค๋ฃจ์ง€ ์•Š์Œ

  • JPA โ† Hibernate โ† Spring Data JPA

Spring Data JPA์˜ ๋“ฑ์žฅ ๋ฐฐ๊ฒฝ

  • ๊ตฌํ˜„์ฒด ๊ต์ฒด์˜ ์šฉ์ด์„ฑ

    • =Hibernate ์™ธ์— ๋‹ค๋ฅธ ๊ตฌํ˜„์ฒด๋กœ ์‰ฝ๊ฒŒ ๊ต์ฒดํ•˜๊ธฐ ์œ„ํ•จ

    • ์ƒˆ๋กœ์šด ๊ตฌํ˜„์ฒด๊ฐ€ ๋‚˜์™€์„œ ๊ต์ฒดํ•  ํ•„์š”๊ฐ€ ์žˆ์„ ๋•Œ ์‰ฝ๊ฒŒ ๊ต์ฒด๊ฐ€๋Šฅ

  • ์ €์žฅ์†Œ ๊ต์ฒด์˜ ์šฉ์ด์„ฑ

    • ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์™ธ์— ๋‹ค๋ฅธ ์ €์žฅ์†Œ๋กœ ์‰ฝ๊ฒŒ ๊ต์ฒดํ•˜๊ธฐ ์œ„ํ•จ

    • ๋งŒ์•ฝ mongoDB๋กœ ๊ต์ฒดํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค๋ฉด ์˜์กด์„ฑ๋งŒ ๊ต์ฒดํ•ด์ฃผ๋ฉด ๋œ๋‹ค

JPA๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฐ€์žฅ ํฐ ์ด์œ ๋Š” ์–ด๋ ค์›Œ์„œ : ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊ณผ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ž˜ ์ดํ•ดํ•ด์•ผํ•จ


์•ž์œผ๋กœ ๋งŒ๋“ค ๊ฒŒ์‹œํŒ์˜ ์š”๊ตฌ์‚ฌํ•ญ ๋ถ„์„

๊ฒŒ์‹œํŒ ๊ธฐ๋Šฅ

  • ๊ฒŒ์‹œํŒ ์กฐํšŒ

  • ๊ฒŒ์‹œ๊ธ€ ๋“ฑ๋ก

  • ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •

  • ๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ

ํšŒ์›๊ธฐ๋Šฅ

  • ๊ตฌ๊ธ€/๋„ค์ด๋ฒ„ ๋กœ๊ทธ์ธ

  • ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž ๊ธ€ ์ž‘์„ฑ ๊ถŒํ•œ

  • ๋ณธ์ธ ์ž‘์„ฑ ๊ธ€์— ๋Œ€ํ•œ ๊ถŒํ•œ ๊ด€๋ฆฌ


ํ”„๋กœ์ ํŠธ์— Spring Data JPA ์ ์šฉํ•˜๊ธฐ

build.gradle

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    annotationProcessor("org.projectlombok:lombok")
    compileOnly("org.projectlombok:lombok")
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('com.h2database:h2')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

spring-boot-starter-data-jpa

  • ์Šคํ”„๋ง ๋ถ€ํŠธ์šฉ Spring Data JPA ์ถ”์ƒํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

  • ์Šคํ”„๋ง ๋ถ€ํŠธ ๋ฒ„์ „์— ๋งž์ถฐ ์ž๋™์œผ๋กœ JPA๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์˜ ๋ฒ„์ „์„ ๊ด€๋ฆฌ

h2

  • ์ธ๋ฉ”๋ชจ๋ฆฌ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

  • ๋ณ„๋„์˜ ์„ค์น˜๊ฐ€ ํ•„์š” ์—†์ด ํ”„๋กœ์ ํŠธ ์˜์กด์„ฑ๋งŒ์œผ๋กœ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ

  • ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ์•ฑ ์žฌ์‹œ์ž‘์‹œ ์ดˆ๊ธฐํ™”(ํ…Œ์ŠคํŠธ ์šฉ๋„๋กœ ๋งŽ์ด ์‚ฌ์šฉ)

src/main/java/com/kyu/book/springboot์— domainํŒจํ‚ค์ง€ ์ƒ์„ฑ

  • ๋„๋ฉ”์ธ = sw์— ๋Œ€ํ•œ ์š”๊ตฌ์‚ฌํ•ญ ํ˜น์€ ๋ฌธ์ œ ์˜์—ญ

domain๋‚ด๋ถ€์— ๊ฒŒ์‹œ๋ฌผ(post)๋ฅผ ์œ„ํ•œ Post.class์ƒ์„ฑ

src/main/java/com/kyu/book/springboot/domain/posts/Posts.class

package com.kyu.book.springboot.domain.posts;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Getter
@NoArgsConstructor
@Entity
public class Posts {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

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

    private String author;

    @Builder
    public Posts(String title, String content, String author){
        this.title = title;
        this.content = content;
        this.author = author;
    }
}

@Entity

  • ํ…Œ์ด๋ธ”๊ณผ ๋งํฌ(๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์—ฐ๊ฒฐ)๋  ํด๋ž˜์Šค์ž„์„ ๋‚˜ํƒ€๋ƒ„

  • SalesManager.java โ†’ sales_manager table

  • ์ด๋Ÿฐ ์‹์œผ๋กœ db์˜ ์ด๋ฆ„์„ ์ง“๋Š”๋‹ค

@Id

  • ํ•ด๋‹น ํ…Œ์ด๋ธ”์˜ Primary Key ํ•„๋“œ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค

@GeneratedValue

  • Primary Key์˜ ์ƒ์„ฑ ๊ทœ์น™์„ ๋‚˜ํƒ€๋ƒ„

  • ์Šคํ”„๋ง ๋ถ€ํŠธ 2.0์—์„œ๋Š” GenerationType.IDENTITY ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•ด์•ผ๋งŒ auto_increment๊ฐ€ ๋จ

@Column

  • ํ…Œ์ด๋ธ”์˜ ์นผ๋Ÿผ์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ ๊ตณ์ด ์„ ์–ธํ•˜์ง€ ์•Š๋”๋ผ๋„ ํ•ด๋‹น ํด๋ž˜์Šค์˜ ํ•„๋“œ๋Š” ๋ชจ๋‘ ์นผ๋Ÿผ์ด ๋จ

  • ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š”, ๊ธฐ๋ณธ๊ฐ’ ์™ธ์— ์ถ”๊ฐ€๋กœ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•œ ์˜ต์…˜์ด ์žˆ์œผ๋ฉด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค

  • ๋ฌธ์ž์—ด์˜ ๊ฒฝ์šฐ์—๋Š” varchar(255)๊ฐ€ ๊ธฐ๋ณธ๊ฐ’์ธ๋ฐ, ์‚ฌ์ด์ฆˆ๋ฅผ 500์œผ๋กœ ๋Š˜๋ฆฌ๊ฑฐ๋‚˜ / ํƒ€์ž…์„ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์„๋•Œ ์‚ฌ์šฉ

@NoArgsConstructor

  • ๊ธฐ๋ณธ ์ƒ์„ฑ์ž ์ž๋™์œผ๋กœ ์ถ”๊ฐ€

  • public Posts(){}์™€ ๊ฐ™์€ ํšจ๊ณผ

@Getter

  • ํด๋ž˜์Šค ๋‚ด ๋ชจ๋“  ํ•„๋“œ์˜ Getter ๋ฉ”์†Œ๋“œ๋ฅผ ์ž๋™ ์ƒ์„ฑ

@Builder

  • ํ•ด๋‹น ํด๋ž˜์Šค์˜ ๋นŒ๋” ํŒจํ„ด ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑ

  • ์ƒ์„ฑ์ž ์ƒ๋‹จ์—์„œ ์„ ์–ธ ์‹œ ์ƒ์„ฑ์ž์— ํฌํ•จ๋œ ํ•„๋“œ๋งŒ ๋นŒ๋”์— ํฌํ•จ

*Entity์˜ primarykey๋Š” Longํƒ€์ž…์˜ auto_increment๋ฅผ ์ถ”์ฒœ

*Entity์—๋Š” ์ ˆ๋Œ€๋กœ Setter ๋ฉ”์†Œ๋“œ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค

  • ์ธ์Šคํ„ด์Šค ๊ฐ’๋“ค์ด ์–ธ์ œ ์–ด๋””์„œ ๋ณ€ํ™˜๋˜๋Š”์ง€ ์ฝ”๋“œ์ƒ์œผ๋กœ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ฐจํ›„ ๊ธฐ๋Šฅ ๋ณ€๊ฒฝ์‹œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊น€

  • ํ•ด๋‹น ํ•„๋“œ์˜ ๊ฐ’ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•˜๋ฉด ๋ช…ํ™•ํžˆ ๊ทธ ๋ชฉ์ ๊ณผ ์˜๋„๋ฅผ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผํ•จ

๊ธฐ๋ณธ์ ์ธ ๊ตฌ์กฐ

์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ตœ์ข… ๊ฐ’์„ ์ฑ„์šด ํ›„ DB์— ์‚ฝ์ž…ํ•œ๋‹ค. ๋˜ํ•œ ๊ฐ’ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํ•ด๋‹น ์ด๋ฒคํŠธ์— ๋งž๋Š” public ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ณ€๊ฒฝ

  • ์—ฌ๊ธฐ์„œ๋Š” @Builder๋ฅผ ํ†ตํ•ด ์ œ๊ณต๋˜๋Š” ๋นŒ๋” ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉ, ๋นŒ๋” ํŒจํ„ด์„ ์ ๊ทน์ ์œผ๋กœ ์‚ฌ์šฉํ•จ

๐Ÿ‘‰Postsํด๋ž˜์Šค๋กœ DB์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ JpaRepository๋ฅผ ์ƒ์„ฑ

src/main/java/com/kyu/book/springboot/domain/posts/PostsRepository.interface

package com.kyu.book.springboot.domain.posts;

import org.springframework.data.jpa.repository.JpaRepository;

public interface PostsRepository extends JpaRepository<Posts, Long> {
}

JPA์—์„œ๋Š” Repository๋ผ๊ณ  ๋ถ€๋ฅด๋ฉฐ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ƒ์„ฑ

JpaRepository<Entityํด๋ž˜์Šค, primary key ํƒ€์ž…>์„ ์ƒ์†ํ•˜๊ฒŒ ๋˜๋ฉด ๊ธฐ๋ณธ์ ์ธ CRUD ๋ฉ”์†Œ๋“œ๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑ

@Repository๋ฅผ ์ถ”๊ฐ€ํ•  ํ•„์š” ์—†์Œ โ†’ Entityํด๋ž˜์Šค์™€ ๊ธฐ๋ณธ Entity Repository๋Š” ํ•จ๊ป˜ ์œ„์น˜

๐Ÿ‘‰Spring Data JPA ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ

src/test/java/com/kyu/book/springboot/domain/posts/PostRepositoryTest.class

package com.kyu.book.springboot.web.domain.posts;

import com.kyu.book.springboot.domain.posts.Posts;
import com.kyu.book.springboot.domain.posts.PostsRepository;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest
public class PostsRepositoryTest {
    @Autowired
    PostsRepository postsRepository;

    @After
    public void cleanup(){
        postsRepository.deleteAll();
    }

    @Test
    public void postsSave_Load(){
        String title = "ํ…Œ์ŠคํŠธ ๊ฒŒ์‹œ๊ธ€";
        String content = "ํ…Œ์ŠคํŠธ ๋ณธ๋ฌธ";

        postsRepository.save(Posts.builder()
						.title(title)
						.content(content)
						.author("kyudo97@naver.com").build());

        List<Posts> postsList = postsRepository.findAll();

        Posts posts = postsList.get(0);
        assertThat(posts.getTitle()).isEqualTo(title);
        assertThat(posts.getContent()).isEqualTo(content);
    }
}

@After

  • Junit์—์„œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚  ๋•Œ๋งˆ๋‹ค ์ˆ˜ํ–‰๋˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ์ง€์ •

  • ๋ณดํ†ต์€ ๋ฐฐํฌ ์ „ ์ „์ฒด ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ๋•Œ ํ…Œ์ŠคํŠธ ๊ฐ„ ๋ฐ์ดํ„ฐ ์นจ๋ฒ”์„ ๋ง‰๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

  • ์—ฌ๋Ÿฌ ํ…Œ์ŠคํŠธ๊ฐ€ ๋™์‹œ์— ์ˆ˜ํ–‰๋˜๋ฉด ํ…Œ์ŠคํŠธ์šฉ db์ธ H2์— ๋ฐ์ดํ„ฐ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋‚จ์•„ ์žˆ์–ด์„œ ๋‹ค์Œ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์‹œ ํ…Œ์ŠคํŠธ ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Œ

postsRepository.save

  • ํ…Œ์ด๋ธ” posts์— insert/update ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰

  • id๊ฐ’์ด ์žˆ๋‹ค๋ฉด update๊ฐ€ / ์—†๋‹ค๋ฉด insert ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰

postsRepository.finaAll

  • ํ…Œ์ด๋ธ” posts์— ์žˆ๋Š” ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•ด์˜ค๋Š” ๋ฉ”์†Œ๋“œ

์—ฌ๊ธฐ์„œ ์‹ค์ œ๋กœ ์‹คํ–‰๋œ ์ฟผ๋ฆฌ๋Š” ์–ด๋–ค ํ˜•ํƒœ์ผ๊นŒ??

โ‡’ ํ•œ ์ค„์˜ ์ฝ”๋“œ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Œ

src/main/resources ๋””๋ ‰ํ† ๋ฆฌ ์•„๋ž˜์—

resourceํŒŒ์ผ ํ˜•ํƒœ, application์ด๋ฆ„์˜ ํŒŒ์ผ์„ ๋งŒ๋“ ๋‹ค

src/main/resources/application.properties

spring.jpa.show_sql=true

์ด๋ ‡๊ฒŒ ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด

๋กœ๊ทธ์—์„œ ์ฟผ๋ฆฌ๋ฅผ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Œ

+MySQL๋ฒ„์ „์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ถ”๊ฐ€

spring.jpa.show_sql=true
spring.jpa.properties.hibernate.dialect=
org.hibernate.dialect.MySQL5InnoDBDialect

Last updated

Was this helpful?