3.2 프로젝트에 Spring Data JPA 적용하기
1. build.gradle에 다음과 같은 의존성들을 등록( dependencies에 )
implementation('org.springframework.boot:spring-boot-starter-data-jpa')
/*
spring-boot-starter-data-jpa
-> 스프링 부트용 Spring Data JPA 추상화 라이브러리
-> 스프링 부트 버전에 맞춰 자동으로 JPA관련 라이브러리들의 버전을 관리
*/
implementation('com.h2database:k2')
/*
h2
-> 인메모리 관계형 데이터 베이스
-> 별도의 설치 없이 프로젝트 의존성만으로 관리할 수 있음.
-> 메모리에서 실행되기 때문에 애플리케이션을 재시작할 때마다 초기화된다는 점을 이용하여 테스트 용도로 많이 사용
*/
2. domain 패키지 생성
domain 패키지 : 도메인을 담을 패키지
여기서 도메인이란?
게시글, 댓글, 회원, 정산, 결제 등 소프트웨어에 대한 요구사항 혹은 문제 영역
그간 xml에 쿼리를 담고, 클래스는 오로지 쿼리의 결과만 담던 일들이 모두 도메인 클래스라고 불리는 곳에서 해결
3. posts 패키지와 클래스 생성
4. Posts 클래스의 코드
package com.jojoldu.book.springboot.domain.posts;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@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 : JPA의 어노테이션
➡ @Getter, @NoArgsConstructor : lombok의 어노테이션
롬복은 코드를 단순화 시켜주지만 필수 어노테이션은 아님
-> 주요 어노테이션인 @Entity를 클래스에 가깝게 둠
-> 코틀린 등의 새 언어 전환으로 롬복이 필요 없을 경우 쉽게 삭제 가능
Posts class
✅ 실제 DB의 테이블과 매칭될 클래스
✅ 보통 Entity 클래스라고 불림
✅ JPA를 사용하면 DB데이터에 작접할 경우 실제 쿼리를 날리기보다는, 이 Entity 클래스의 수정을 통해 작업
Posts 클래스의 JPA에서 제공하는 어노테이션s
1. @Entity
➡ 테이블과 링크될 클래스임을 나타냄
➡기본값으로 클래스의 카멜케이스 이름을 언더스코어 네이밍(_)으로 테이블 이름을 매칭
➡ ex) SalesManager.java -> sales_manager table
2. @Id
➡ 해당 테이블의 PK 필드를 나타냄
3. @GeneratedValue
➡ PK의 생성 규칙을 나타냄
4. @Column
➡ 테이블 컬럼을 나타내며 굳이 선언하지 않더라도 해당 클래스의 필드는 모두 칼럼
➡ 사용하는 이유는, 기본값 외에 추가로 변경이 필요한 옵션이 있으면 사용
➡ 문자열의 경우 VARCHAR(255)가 기본값인데, 사이즈를 500으로 늘리고 싶거나(ex:title), 타입을 TEXT로 변경하고 싶거나(ex:content) 등의 경우에 사용
Posts 클래스의 롬복 라이브러리의 어노테이션s
5. @NoArgsConstructor
➡ 기본 생성자 자동추가
➡ public Posts() {}와 같은 효과
6. @Getter
➡ 클래스 내 모든 필드의 Getter 메소드를 자동생성
7. @Builder
➡ 해당 클래스의 빌더 패턴 클래스를 생성
➡ 생성자 상단에 선언 시 생성자에 포함된 필드만 빌더에 포함
서비스 초기 구축 단계에서 테이블 설계(Entity 설계)가 빈번하게 변경됨
-> 이때 롬복의 어노테이션들이 코드 변경량을 최소화
✅ 이 Posts 클래스에는 한 가지 특이점이 있음
➡ Setter 메소드가 없음
➡ getter/setter를 무작정 생성하면 해당 클래스의 인스턴스 값들이 언제 어디서 변해야 하는지 코드상으로 명확하게 구분할 수가 없어, 차후 기능 변경 시 복잡해짐
➡ 그래서 Entity 클래스에는 절대 Setter 메소드를 만들지 않음
➡ 해당 필드의 값이 변경이 필요하면 명확히 그 목적과 의도를 나타낼 수 있는 메소드를 추가해야 함
ex) 주문 취소 메소드
잘못된 사용 예시
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.cancelOrder();
}
Q. 그렇다면 setter가 없는 이 상황에서 어떻게 값을 채워 DB에 삽입?
A. 기본적인 구조는 생성자를 통해 최종값을 채운 후 DB에 삽입하는 것이며, 값 변경이 필요한 경우 해당 이벤트에 맞는 public 메소드를 호출하여 변경하는 것을 전제로 함
책에서는 생성자 대신 @Builder를 통해 제공되는 빌더 클래스 사용
➡ 생성자나 빌더나 생성 시점에서 값을 채워주는 역할이지만,
생성자의 경우 지금 채워야 할 핑드가 무엇인지 명확히 지정할 수 없음
예를 들어,
개발자가 new Example(b,a)처럼 a,b의 위치를 변경해도 코드를 실행하기 전까지 문제를 찾을 수 없음
public Example(String a,String b){
this.a=a;
this.b=b;
}
하지만 빌더를 사용하게 되면,
다음과 같이 어느 필드에 어떤 값을 채워야할지 명확하게 인지할 수 있음.
Example.builder()
.a(a)
.b(b)
.build();
5. Posts 클래스로 Database를 접근하게 해줄 JpaRepository 생성
import org.springframework.data.jpa.repository.JpaRepository;
public interface PostsRepository extends JpaRepository<Posts, Long> {
}
- 보통 ibatis나 MyBatis 등에서 Dao라고 불리는 DB Layer 접근자.
- JPA에선 Repository라고 부르며 인터페이스로 생성
- 단순히 인터페이스를 생성 후, JpaRepository<Entity 클래스, PK타입>를 상속하면 기본적인 CRUD 메소드가 자동으로 생성
- @Repository를 추가할 필요도 없음
- 주의할 점은 Entity 클래스와 기본 Entity Repository는 함께 위치해야 함. 둘은 아주 밀접한 관계이고, Entity 클래스는 기본 Repository 없이는 제대로 역할을 할 수가 없음
- 나중에 프로젝트 규모가 커져 도메인 별로 프로젝트를 분리해야 한다면 이때 Entity 클래스와 기본 Repository는 함께 움직여야 하므로 도메인 패키지에서 함께 관리
출처 : 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 [이동욱 지음]
'Back-End > Springboot와 AWS로 혼자 구현하는 웹 서비스' 카테고리의 다른 글
Chapter 04. 머스테치로 화면 구성하기 (1) (0) | 2022.03.15 |
---|---|
Chapter 03. SpringBoot에서 JPA로 데이터베이스 다뤄보자 (5) (0) | 2022.03.14 |
Chapter 03. SpringBoot에서 JPA로 데이터베이스 다뤄보자 (4) (1) | 2022.03.13 |
Chapter 03. SpringBoot에서 JPA로 데이터베이스 다뤄보자 (3) (0) | 2022.03.12 |
Chapter 03. SpringBoot에서 JPA로 데이터베이스 다뤄보자 (1) (0) | 2022.03.12 |