스프링 부트와 AWS로 혼자 구현하는 웹 서비스: (3) 스프링 부트에서 JPA로 데이터베이스를 다뤄보자

지니어스현·2022년 6월 2일
0

JPA 소개

서로 지향하는 바가 다른 객체지향 프로그래밍 언어와 관계형 데이터베이스의 중간에서 패러다임을 일치시켜주기 위한 언어

  • 개발자는 객체지향적으로 프로그래밍을 하고, JPA가 이를 관계형 데이터베이스에 맞게 SQL을 대신 생성해서 실행한다. 개발자는 항상 객체지향적으로 코드를 표현할 수 있으니 더는 SQL에 종속적인 개발을 하지 않아도 된다.

Spring Data JPA

JPA: 인터페이스, 자바 표준 명세서
구현체: Hibernate, Eclipse Link
스프링에서 JPA를 사용할 때는 이 구현체들을 직접 다루지 않고, 구현체들을 좀 더 쉽게 사용하고자 추상화시킨 Spring Data JPA라는 모듈을 이용한다.

프로젝트에 Spring Data Jpa 적용하기

Posts.java

package com.geniushyeon.springboot.domain.posts;

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

import javax.persistence.*;

@Getter // setter 사용 X
@NoArgsConstructor
@Entity // 테이블과 링크될 클래스임을 나타냄
public class Posts {

    @Id // pk
    @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;
    }
}

Setter가 없는 상황에서 DB에 값을 삽입할 때

  • 생성자를 통해 최종 값을 채운 후 DB에 삽입한다.
  • 값 변경이 필요한 경우 해당 이벤트에 맞는 public 메소드를 호출하여 변경하는 것을 전제로 한다.

Builder 패턴

생성자나 빌더나 생성 시점에 값을 채워주는 역할은 똑같지만, 생성자의 경우 지금 채워야 할 필드가 무엇인지 명확하게 지정할 수 없다.
빌더를 사용하게 되면 어느 필드에 어떤 값을 채워넣는지 명확하게 인지할 수 있다.

JpaRepository 기본 형태

PostsRepository.java

package com.geniushyeon.springboot.domain.posts;

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

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

인터페이스로 생성한 후 JpaRepository<Entity, PK>를 상속하면 기본적인 CRUD 메소드가 자동으로 생성됨

주의사항

  • Entity 클래스와 Entity Repository는 함께 위치해야 한다.

Spring Data JPA 테스트 코드 작성

PostsRepositoryTest.java

package com.geniushyeon.springboot.domain.posts;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.util.List;

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

@ExtendWith(SpringExtension.class)
@SpringBootTest
public class PostsRepositoryTest {

    @Autowired
    PostsRepository postsRepository;

    @AfterEach
    public void cleanup() { // 매 테스트 메소드 후 실행
        postsRepository.deleteAll();
    }

    @Test
    public void 게시글저장_불러오기() {

        // given
        String title = "테스트 제목";
        String content = "테스트 본문";

        postsRepository.save(Posts.builder()
                .title(title)
                .content(content)
                .author("geniushyeon@github.com")
                .build());

        // when
        List<Posts> posts = postsRepository.findAll();

        // then
        Posts post = posts.get(0);
        assertThat(post.getTitle()).isEqualTo(title);
        assertThat(post.getContent()).isEqualTo(content);

    }
}

application.properties 작성

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
spring.jpa.properties.hibernate.dialect.storage_engine=innodb
spring.datasource.hikari.jdbc-url=jdbc:h2:mem:testdb;MODE=MYSQL
spring.datasource.hikari.username=sa

등록/수정/조회 API 만들기

Spring Web Layers

Web, Service, Repository, Dto, Domain 5가지 레이어에서 비즈니스 처리를 담당해야 할 곳은 Domain이다.
서비스 메소드는 트랜잭션도메인 간의 순서만 보장해 준다.

Bean 의존성 - 생성자 주입

@RequiredArgsConstructor

  • final이 선언된 모든 필드를 인자값으로 하는 생성자를 생성해 준다.

JPA의 영속성 컨텍스트

영속성 컨텍스트: 엔티티를 영구 저장하는 환경
JPA의 핵심 내용은 엔티티가 영속성 컨텍스트에 포함되어 있느냐 아니냐로 갈린다.
Entity 객체의 값만 변경하면 별도로 update 쿼리를 날릴 필요가 없다.

profile
넓은 바다에서 유영하는 범고래

0개의 댓글