SpringBoot에서 JPA 사용하기

8420 단어 SpringbootSpringboot

OVERVIEW

이번 포스팅에서는 SpringBoot에서 실제로 JPA를 사용하기 위한 설정, 코드작성과 간단한 테스트를 실행해본다.

SpringBoot에 JPA 적용하기

1. 의존성 추가

우선 build.gradle 하단에 dependencies에 위에 2줄을 추가한다.

  • spring-boot-starter-data-jpa
    • 스프링 부트용 Spring Data JPA 추상화 라이브러리
    • 스프링 부트 버전에 맞춰 자동으로 JPA관련 라이브러리 버전을 관리해준다.
  • h2
    • 별도의 설치없이 프로젝트 의존성만으로 관리 가능한 인메모리 관계형 데이터베이스
    • 인메모리이기 때문에 애플리케이션을 재시작 할 때 초기화되며 테스트용으로 많이 사용한다.

2. 패키지 생성

의존성을 추가하였다면 Posts라는 도메인 클래스를 생성한다.

  • domain
    • domain이란 소프트웨어의 요구사항 혹은 문제영역이라고 할 수 있다.
    • 기존에 SQLMapper를 사용할 때 xml파일에 SQL을 작성하고 클래스에 쿼리의 결과를 담는 과정이 domain클래스에서 모두 해결된다.

3. Entity클래스 작성

Posts 클래스의 내용은 위와 같다.
내용을 하나하나 살펴보자.

  • @Getter
    • 필드변수의 Getter를 생성해주는 롬복 어노테이션이다.
  • @NoArgsConstructor
    • 매개변수 없는 생성자를 만들어주는 롬복 어노테이션이다.
    • 여기서는 public Posts() {} 와 같다.
  • @Entity
    • 해당 클래스가 DB테이블과 매칭될 클래스라는 의미이다.
    • 해당 어노테이션이 있는 클래스를 Entity클래스라고도 부른다.
    • JPA를 사용하면 DB데이터에 작업을 할 때 Entity클래스를 수정하여 작업한다.
    • 클래스의 카멜케이스와 테이블의 언더바를 매핑한다.
      ex) SalesManager.java -> sales_manager table
  • @Id
    • 해당 테이블의 PK 필드를 나타낸다.
  • @GeneratedValue
    • PK 생성 규칙을 의미한다.
    • 스프링 부트 2.0 에서는 GenerationType.IDENTITY 옵션을 추가해야만 auto_increment가 된다.
  • @Column
    • 테이블의 컬럼을 나타낸다.
    • Entity클래스의 필드변수들은 기본적으로 Column이 되지만 기본값 외에 추가로 변경이 필요한 옵션이 있는경우에 사용한다.
      ex) 문자열의 경우 VARCHAR(255)가 기본값이지만, 사이즈를 500으로 늘리거나 타입을 TEXT로 변경하는 등의 작업을 할 때 사용한다.
  • @Builder
    • 해당 클래스의 빌더 패턴 클래스를 생성하는 롬복 어노테이션이다.
    • 생성자 상단에 선언하면 샌성자에 포함된 필드만 빌더에 포함된다.

Posts클래스에는 Setter가 없다.
왜 Setter를 만들지 않고 Builder패턴을 사용하는 것일까?

첫 번째 Entity클래스에 Setter가 없는 이유는 해당 클래스의 인스턴스 값들이 언제 어디서 변해야 하는지 코드상으로 명확하게 구분할 수 없기 때문이다.
Setter를 사용하지 않는 대신 해당 필드의 값 변경이 필요한 경우 명확한 목적과 의도를 나타낼 수 있는 메소드를 추가해서 사용해야 한다.
올바른예시와 잘못된 예시를 들어보자.

[잘못된 예시]

public class Order {
  public void setStatus(boolean status) {
      this.status = status;
  }
}

public void 주문서비스_취소이벤트() {
	order.setStatus(false);
}	

[올바른 예시]

public class Order {
  public void cancelOrder() {
      this.status = false;
  }
}

public void 주문서비스_취소이벤트() {
	order.cancelOder();
}

이 부분을 읽으면서 개인적으로 책을 구매하기 잘했다는 생각을 했다.
잘못된 예시는 너무나도 흔히 사용하는 코드이기 때문이다.
사실 두 가지를 비교하기 전에는 잘못된 예시가 뭐가 문제지? 라는 생각이었다.
하지만 목적과 의도를 명확하게 나타내는 메소드를 만들어서 사용하는것이 얼마나 코드를 읽기 편하개 만들어주는지 알 수 있었다.

두 번째 Builder패턴을 사용하는 이유 역시 명확성을 위해서다.
Builder패턴을 사용하면 어떤 필드에 어떤 값을 넣는지 명확하게 알 수 있지만 생성자를 사용할 경우에는 어떤 필드에 어떤 값을 넣는지 명확하게 알 수 없다.
생성자를 이용하는 방법과 Builder패턴을 사용하는 경우를 비교하는 예제는 작성하지 않는다.

4. JpaRepository 작성

JpaRepository는 Entity클래스로 Database를 접근하게 해준다.
MyBatis를 사용할 때 만드는 Dao라고 얘기하는 DB Layer 접근자와 매핑되는 개념이다.

JPA는 Interface로 생성하며 JpaRepository<Entity 클래스, PK 타입>를 상속하면 기본적인 CRUD 메소드가 자동으로 생성된다.
@Repository를 별도로 추가하지 않아도 된다.
여기서 주의점은 Entity클래스와 JpaRepository는 같은 곳에 위치 해야한다는 것이다.
둘은 아주 밀접한 관계이며 Repository없이는 Entity클래스는 제 역할을 할 수 없기 때문이다.
그래서 이 둘은 Domain패키지에서 함께 관리한다.

5. H2 데이터베이스로 테스트 하기

여기까지 JPA를 사용하기 위해 의존성을 추가하고, Entity클래스와 JpaRepository를 생성하였다.
의존성 추가시에 함께 추가한 H2 데이터베이스를 이용하여 잘 동작하는지 테스트 해보자.

savefindAll기능을 테스트 하는 코드다.
Junit 사용방법은 이전 포스팅을 참고하면 된다.
별다른 설정없이 @SpringBootTest를 사용하면 H2 데이터베이스를 자동으로 실행해 준다.
여기서는 처음 사용해보는 어노테이션과 Jpa의 메소드에 대해서만 간략히 설명한다.

  • @After
    • Junit에서 단위 테스트가 끝날 때 마다 실행할 메소드를 지정하는 어노테이션이다.
    • 보통 배포 전 전체 테스트를 수행할 때 테스트 간 데이터 침범을 막기위해 많이 사용한다.
    • 여기서는 단위 테스트가 끝날 때 마다 H2 데이터 베이스를 초기화 하는데 사용하고 있다.
  • postsRepository.save
    • 테이블 Posts에 insert/update 쿼리를 수행한다.
    • id(pk)값이 존재한다면 update, 존재하지 않는다면 insert를 수행한다.
  • postsRepository.findAll
    • SELECT * FROM POSTS와 동일하다.

만약 실제로 수행되는 쿼리가 궁금하다면 application.properties에 간단한 설정을 추가하면 된다.

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

첫 번째 설정은 실행된 쿼리문을 콘솔에 보여준다는 설정이다.
두 번째 설정은 쿼리문을 MySQL문법으로 보겠다는 설정이다.
두 번째 설정을 하지 않으면 H2 데이터베이스 문법이 적용되기 때문에 우리가 기대한 쿼리와 다른 결과가 나올 수 있으니 두 가지 설정 모두 적용하자.

SUMMARY

  • Entity클래스는 실제 데이터베이스 테이블과 매핑되는 클래스이다.
  • Entity클래스로 데이터베이스 접근을 가능하게 해주는것은 JpaRepository이다.
  • JpaRepository는 MyBatis의 Dao(DB Layer)와 매핑되는 개념이다.
  • Entity클래스와 JpaRepository는 같은 곳에 위치해야 하며 보통 Domain Package에서 함께 관리한다.
  • JpaRepository는 Interface로 만들며
    JpaRepository<Entity 클래스, PK 타입>를 상속하면 기본적인 CRUD메소드가 자동생성 된다.
  • 테스트용으로 H2 데이터베이스를 활용하며 데이터 침범이 일어나지 않도록 주의해야 한다.

좋은 웹페이지 즐겨찾기