DEV/Spring

[JPA] JPA 세팅, h2(인메모리 관계형 데이터 베이스), 어노테이션정리

꼭두새벽에비명소리 2020. 2. 18. 11:17

인텔리J , Gradle

  • build.gradle에 의존성 등록 (dependencies 에 추가)


    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('com.h2database:h2')
    • spring-boot-starter-data-jpa

      • 스프링부트용 Spring Data Jpa 추상화 라이브러리

      • 스프링부트버전에 맞춰서 자동으로 JPA 관련 라이브러리들의 버전을 관리해 줌

    • h2

      • 인메모리 관계형 데이터 베이스

      • 별도의 설치가 필요없이 프로젝트 의존성만으로 관리가능

      • 메모리에서 실행되기 때문에 재시작할때마다 초기화된다. 그래서 테스트 용도로 많이사용



JPA 예제

  1. Entity클래스 (Posts.java)


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

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

import javax.persistence.*;

/*
* @Entity
* - 테이블과 링크될 클래스임을 나타낸다
* - 카멜케이스이름을 언더스코어 네이밍으로 테이블 이름을 매칭
*     ex) SaleManager.java -> sales_manager (table)
*
* @NoArgsConstructor
* - 롬복의 어노테이션으로 기본 생성자 자동 추가
*
* @Getter
* - 모든 필드의 Getter 메서드 생성
*/
@Getter
@NoArgsConstructor
@Entity
public class Posts {

   /*
       @ Id
           - 해당 테이블의 PK

       @GeneratiedValue
           - PK의 생성 규칙
           - GenerationType.IDENTITY를 추가해야만 auto_increment가 된다

       @Column
           - 테이블의 컬럼을 나타내며, 굳이 선언하지 않아도 해당클래스의 필드는 모두 컬럼이 된다.
           - 사용하는 이유는, 기본값 외에 추가로 변경이 필요한 옵션이 있을때 사용
           - 문자열은 VARCHAR(255)가 기본값이지만,
             사이즈를 늘리거나 (length=500)
             타입을 텍스트로 변경(ex:content)하고 싶을 때 사용 (columnDefinition="TEXT")
    */
   @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
   // 롬복 어노테이션으로 해당 클래스의 빌더 패턴 클래스를 생성
   // 생성자 상단에 선언시 생성자에 포함된 필드만 빌더에 포함
   @Builder
   public Posts(String title, String content, String author) {
       this.title = title;
       this.content = content;
       this.author = author;
  }
}
  • Entity 클래스에는 절대 Setter를 만들지 않는다.

    • 해당 필드의 값 변경이 필요하면 명확히 그 목적과 의도를 나타낼 수 있는 메서드를 추가해야 한다.

  • @Builder 를 통해 최종값을 채운 후 DB에 삽입

    • 생성자나 빌더나 역할은 같지만, 빌더는 어떤 필드에 어떤 값을 채워야 할 지 명확하게 인지할 수 있다


      // 생성자 (new Example(b,a)) 로 실수하면 실행전까지 문제 못찾는다
      public Example(String a, String b) {
       this.a = a;
       this.b = b;
      }

      // 빌더 (명확하다)
      Example.builder()
      .a(a)
      .b(b)
      .build();





  1. JapRepository 생성 ( DB에 접근하게 해줄 PostsRepository 인터페이스)


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

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

    public interface PostsRepository extends JpaRepository<Posts,Long> {
     
    }
    • ibatis 나 MyBatis에서는 Dao 라고 불리는게 JPA에서는 Repository라 부른다

    • 단순히 인터페이스 생성후, JpaRepository<Entity 클래스, PK타입> 을 상속하면 CRUD메서드가 자동 생성된다

    • @Repository를 추가할 필요도 없다

    • 주의할 점은 Entity 클래스와동일한 위치에 있어야 한다.






  1. JPA 테스트 ( save, findAll 기능 )

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

    import org.junit.After;
    import org.junit.Assert;
    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.Assertions.assertThat;

    /*
       @SpringBootTest
           -별도의 설정없이 H2 데이터베이스를 자동을 실행시켜줌
    */
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class PostsRepositoryTest {

       @Autowired
       PostsRepository postsRepository;

       /*
           @After
               - Junit에서 단위테스트가 끝날때마다 수행되는 메서드
        */
       @After
       public void cleanup() {
           postsRepository.deleteAll();
      }

       @Test
       public void 게시글저장_불러오기() {
           //given
           String title = "테스트 게시글";
           String content = "테스트 본문";

           /*
               테이블 posts에 insert/update 쿼리를 실행
               id가 있으면 update , 없으면 insert
            */
           postsRepository.save(Posts.builder()
                  .title(title)
                  .content(content)
                  .author("anse@gmail.com")
                  .build()
          );

           //when
           /*
               테이블 posts에 있는 모든 데이터 조회
            */
           List<Posts> postsList = postsRepository.findAll();

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





어노테이션 정리

@Entity

  • 테이블과 링크될 클래스임을 나타냄

  • 카멜케이스이름을 언더스코어 네이밍으로 테이블 이름 매칭

    • ex) SaleManager.java -> sales_mansger

@NoArgsConstructor

  • 롬복의 어노테이션으로 기본 생성자 자동으로 생성

@Id

  • 해당 테이블의 PK

@GeneratedValue

  • PK의 생성규칙

  • GenerationType.IDENTITY를 추가해야만 auto_increment가 됨

@Column

  • 테이블의 컬럼 (굳이 안써도 해당클래스의 필드는 모두 컬럼이 된다)

  • 사용하는 이유는, 기본값 외에 추가로 변경이 필요한 옵션이 있을때

    • ex)문자열의 기본은 VARCHAR(255) 이지만 사이즈를 늘리고 싶거나 (length=500)

    • ex)타입을 텍스트로 변경하고 싶을때 (columnDefinition="TEXT")

@Builder

  • 롬복 어노테이션, 해당 클래스의 빌더 패턴 클래스를 생성

  • 생성자 상단에 선언시 생성자에 포함된 필드만 빌더에 포함