[03] 스프링 부트에서 JPA로 데이터베이스 다루기(00~02)
00. 목표
JPA라는 자바 표준 ORM(Object Relational Mapping) 기술 사용하기
- ORM: 객체를 매핑하는 것
- SQL Mapper: 쿼리를 매핑하는 것
01. JPA 소개
✨관계형 데이터베이스(RDB)의 문제점
- 단순 반복 작업
- 패러다임 불일치
- 관계형 데이터베이스는 어떻게 데이터를 저장할지에 초점
- 객체지향 프로그래밍 언어는 메시지를 기반으로 기능과 속성을 한 곳에서 관리
=> 웹 애플리케이션 개발은 점점 데이터 베이스 모델링에만 집중하게 됨. 이런 문제점을 해결하기 위해 JPA 등장
✨JPA의 등장
- 개발자는 객제지향적으로 프로그래밍을 하고, JPA가 이를 관계형 데이터베이스에 맞게 SQL을 대신 생성해서 실행
- 그 결과로 SQL에 종속적인 개발을 하지 않아도 됨
- 생산성 향상은 물론 유지 보수가 용이해짐
✨Spring Data JPA
-
JPA는 인터페이스로서 자바 표준 명세서로서 JPA를 사용하기 위해서는 구현체가 필요함
ex) Hibernate, Eclipse Link -
Spring에서 JPA를 사용할 때는 이러한 구현체를 직접 다루지 않음
-> 구현체들을 좀 더 쉽게 사용하고자 추상화 시킨 Spring Data JPA라는 모듈을 이용하여 JPA 기술을 다룸JPA <- Hibernate <- Spring Data JPA
-
Spring Data JPA가 등장한 이유
- 구현체 교체의 용이성
: Hibernate 외에 다른 구현체로 쉽게 교체하기 위함 - 저장소 교체의 용이성
: 관계형 데이터베이스 외에 다른 저장소로 쉽게 교체하기 위함(의존성만 교체하면 됨)
✨요구사항 분석
앞으로 만들어나갈 게시판의 요구사항
1. 게시판 기능
- 게시글 조회 / 등록 / 수정 / 삭제
2. 회원 기능
- 구글 / 네이버 로그인
- 로그인한 사용자 글 작성 권한
- 본인 작성 글에 대한 권한 관리
02. 프로젝트에 Spring Data JPA 적용하기
2-1) build.gradle에 의존성 등록
compile('org.springframework.boot:spring-boot-starter-data-jpa') // 1.
compile('com.h2database:h2') //2.
1. spring-boot-starter-data-jpa
- 스프링 부트용 Spring Data JPA 추상화 라이브러리
- 스프링 부트 버전에 맞춰 자동으로 JPA 관련 라이브러리들의 버전을 관리해줌
2. h2
- 인메모리 관계형 데이터베이스
- 별도의 설치가 필요없이 프로젝트 의존성만으로 관리 가능
- 메모리에서 실행되기 때문에 애플리케이션을 재시작할 때마다
초기화된다는 점을 이용하여 테스트 용도로 많이 사용됨- 여기서는 JPA의 테스트, 로컬 환경에서의 구동에서 사용할 예정
2-2) domain 패키지 생성
: 도메인을 담을 패키지
- 도메인: 게시글, 댓글, 회원, 정산, 결제 등 소프트웨어에 대한 요구사항 혹은 문제 영역
2-3) domain 패키지에 posts패키지와 Posts 클래스 생성
여기서 Posts 클래스는 실제 DB의 테이블과 매칭될 Entity 클래스로, JPA를 사용하면 이 Entity 클래스의 수정을 통해 작업함
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Getter // 6.
@NoArgsConstructor // 5.
@Entity // 1.
public class Posts {
@Id // 2.
@GeneratedValue(strategy = GenerationType.IDENTITY) // 3.
private Long id;
@Column(length = 500, nullable = false) // 4.
private String title;
@Column(columnDefinition = "TEXT", nullable = false)
private String content;
private String author;
@Builder // 7.
public Posts(String title, String content, String author){
this.title = title;
this.content = content;
this.author = author;
}
}
✔ JPA에서 제공하는 어노테이션
1. @Entity
- 테이블과 링크될 클래스임을 나타냄
- 기본값으로 클래스의 카멜케이스 이름을 언더스코어 네이밍(_)으로 테이블 이름을 매칭함
ex) SalesManager.java -> sales_manager table2. @Id
- 해당 테이블의 PK 필드
3. @GeneratedValue
- PK의 생성 규칙을 나타냄
- 스프링 부트 2.0에서는 GernerationType.IDENTITY 옵션을 추가해야 auto_increment가 됨
4. @Column
- 테이블의 칼럼을 나타내며 굳이 선언하지 않아도 해당 클래스의 필드는 모두 칼럼이 됨
- 기본값 외에 추가로 변경이 필요한 옵션이 있을 때 사용
- 문자열의 경우 VARCHAR(255)가 기본값인데, 사이즈를 500으로 늘리고 싶거나(ex: title), 타입을 TEXT로 변경하고 싶거나(ex: content) 등의 경우에 사용됨
❗ 참고
웬만하면 Entity의 PK는 Long타입의 Auto_increment 추천
(MySQL 기준으로 이렇게 하면 bitint 타입이 됨).
유니크 키나 복합키로 PK를 잡을 경우 종종 난감한 상황 발생
- FK를 맺을 때 다른 테이블에서 복합키 전부를 갖고 있거나, 중간 테이블을 하나 더 둬야 하는 상황 발생
- 인덱스에 좋은 영향 끼치지 x
- 유니크한 조건이 변경될 경우 PK 전체를 수정해야 함
=> 주민등록번호, 복합키 등은 유니크 키로 별도로 추가하는 것 추천 ❗
✔ 롬복 라이브러리의 어노테이션
서비스 초기 구축 단계에선 테이블 설계(Entity 설계)가 빈번하게 변경되는데, 이때 롬복의 어노테이션들은 코드 변경량을 최소화시켜줌
5. @NoArgsConstructor
- 기본 생성자 자동 추가
- public Posts(){}와 같은 효과
6. @Getter
- 클래스 내 모든 필드의 Getter 메소드를 자동생성
7. @Builder
- 해당 클래스의 빌더 패턴 클래스를 생성
- 생성자 상단에 선언 시 생성자에 포함된 필드만 빌더에 포함
❗ Setter 메소드를 만들지 않는 이유
-
getter/setter를 무작정 생성하는 경우, 해당 클래스의 인스턴스 값들이 언제 어디서 변해야 하는지 코드상으로 명확하게 구분할 수 없음 -> 차후 기능 변경 시 복잡
-
그래서 Entity 클래스에서는 Setter 메소드를 절대 만들지 않음
: 대신, 해당 필드의 값 변경이 필요하면 명확히 그 목적과 의도를 나타낼 수 있는 메소드를 추가해야 함 -
ex) 주문 취소 메소드 만드는 경우
public class Order{
public void cancelOrder(){
this.state = false;
}
}
public void 주문서비스의_취소이벤트(){
order.cancelOrder();
}
❓ Setter 없는 상황에서 DB에 값 삽입하는 법
- 기본적인 구조는 생성자를 통해 최종값을 채운 후 DB에 삽입하는 것이고, 값 변경이 필요한 경우 해당 이벤트에 맞는 public 메소드를 호출하여 변경
public Example(String a, String b){
this.a = a; // new Example(b,a)처럼
this.b = b; // a와 b의 위치를 변경해도
} // 코드 실행전 까진 모름
- 생성자 대신에 @Builder를 통해 제공되는 빌더 클래스 사용
: 빌더는 어느 필드에 어떤 값을 채워야 할지 명확히 지정할 수 있음 (생성자는 x)
Example.builder().a(a)
.b(b)
.build();
2-4) Posts 클래스로 DB 접근하게 해줄 JpaRepository 생성
+) 인터페이스 생성하는 법
: Java Class > Interface
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를 추가할 필요도x
-
(❗) Entity 클래스와 기본 Entity Repository는 함께 위치해야 함
: Entity 클래스는 기본 Entity Repository 없이는 제대로 역할x
Author And Source
이 문제에 관하여([03] 스프링 부트에서 JPA로 데이터베이스 다루기(00~02)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@cutehuman/03-스프링-부트에서-JPA로-데이터베이스-다루기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)