본문 바로가기
스프링부트와 AWS

#4_스프링 부트에서 JPA로 데이터베이스 다루기

by Meaning_ 2021. 8. 5.
728x90
반응형

JPA


JPA는 자바 표준 ORM이다.

웹 애플리케이션에서 관계형데이터베이스 (RDB)는 빠질 수 없는 요소이다. Oracle,MySQL,MSSQL 등을 쓰지 않은 웹 애플리케이션은 거의 없다. 

관계형 데이터베이스는 어떻게 데이터를 저장할지에 초점이 맞춰진 기술이지만, 객체지향 프로그래밍은 기능과 속성을 한 곳에서 관리하는 기술이다. 서로 지향하는 바가 다른 2개 영역을 중간에서 패러다임 일치 시켜주기 위한 기술이 JPA이다. 

개발자는 객체지향 프로그래밍을 하고, JPA가 관계형 데이터베이스에 맞게 SQL을 대신 생성해서 실행한다. 

 

cf) ORM이란?

 

객체 - 관계 매핑으로, 객체와 관계형 데이터베이스의 데이터를 자동으로 매핑(연결)해주는 것을 말한다.

객체지향 프로그래밍은 클래스를 사용하고, 관계형 데이터베이스는 테이블을 사용한다. 그러므로 객체모델과 관계형 모델간에 불일치가 존재한다.ORM을 통해 객체 간의 관계를 바탕으로 SQL을 자동으로 생성하여 불일치를 해결한다.

 

<참고자료>

https://gmlwjd9405.github.io/2019/02/01/orm.html

 

[DB] ORM이란 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

 

Spring Data JPA


인터페이스인 JPA를 사용하기 위해서는 구현체가 필요하다. 대표적으로 Hibernate,Eclispe,Link등이 있다. 하지만 Spring에서 JPA를 사용할 때는 이 구현체들을 직접 다루지 않는다. 구현체들을 더 쉽게 사용하고자 추상화시킨 Spring Data JPA 모듈을 이용하여 JPA기술을 다룬다. 

 

JPA <-Hibernate <- Spring Data JPA

 

+)  JPA와 Hibernate는 자바의 interface와 interface를 구현한 class와 같은 관계이다.

 

<참고자료>

https://suhwan.dev/2019/02/24/jpa-vs-hibernate-vs-spring-data-jpa/

 

JPA, Hibernate, 그리고 Spring Data JPA의 차이점

개요 Spring 프레임워크는 어플리케이션을 개발할 때 필요한 수많은 강력하고 편리한 기능을 제공해준다. 하지만 많은 기술이 존재하는 만큼 Spring 프레임워크를 처음 사용하는 사람이 Spring 프레

suhwan.dev

 

Hibernate와 Spring Data JPA를 쓰는 것에는 큰 차이가 없는데, Spring Data JPA가 등장한 이유는 무엇일까?

크게 두가지로 나뉘는데

 

1. 구현체 교체의 용이성

2. 저장소 교체의 용이성

 

구현체 교체의 용이성이란 Hibernate 외에 다른 구현체로 쉽게 교체하기 위함이다.

Hibernate가 언젠가 수명을 다해서 새로운 JPA 구현체가 대세로 떠오를 때, Spring Data JPA 를 쓰는 중이라면 아주 쉽게 교체할 수 있다.

 

저장소 교체의 용이성이란 관계형 데이터베이스 외에 다른 저장소로 쉽게 교체하기 위함이다. 서비스 초기에는 관계형 데이터베이스로 모든 기능을 처리했지만, 점점 트래픽이 많아져 관계형 데이터베이스로는 도저히 감당히 안될때가 있을 수 있다. 이때 MongoDB로 교체가 필요하다면 개발자는 Spring Data JPA에서 Spring Data MongoDB로 의존성만 교체하면된다. 

 

Spring Data의 하위 프로젝트는 기본적인 CRUD 인터페이스가 같기 때문인데 즉, Spring Data JPA, Spring Data Redis,Spring Data MongoDB등등 Spring Data의 하위 프로젝트들은 save(),findAll(),findOne() 등을 인터페이스로 갖고 있다. 그렇기 때문에 저장소가 교체되어도 기본적인 기능은 변경할 것이 없다. 

 

+) CRUD 란 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인 Create(생성, SQL에서는 INSERT), Read(읽기,SQL에서는 SELECT),Update(갱신,SQL에서는 UPDATE),Delete(삭제,SQL에서는 DELETE)를 묶어서 일컫는 말이다.

 

+) MongoDB 는 필요한 쿼리 제공 및 인덱싱을 활용해 원하는 수준의 확장성과 유연성을 제공하는 문서 데이터베이스fh, document/base/open source의 3가지 특징을 가지고 있다. 

 

+)MongDB는 NoSQL 진영에 있는데 Redis또한 이 진영에 속해있다. NoSQL은 SQL을 사용하는 관계형 데이터베이스가 아닌 데이터 베이스를 의미한다. 반대로 관계형 데이터 베이스는 앞서 말한 것 처럼 MySQL,Oracle이 있다. 

 

<참고자료>

https://livedata.tistory.com/3

 

[데이터베이스] CRUD란? (Create,Read,Update,Delete)

흔히들 소프트웨어를 만들때 "CRUD 써서 하고" 라는 말을 많이 합니다. 저도 처음들었을 때 이게뭐지? 당황할 수 있는데 전혀 그럴 필요 없습니다. 지금부터 알면 되니까요 하하 ( "이것도 몰라?"

livedata.tistory.com

https://kciter.so/posts/about-mongodb

 

MongoDB 이해하기

사내에서 MongoDB를 잘 쓰기위한 스터디를 하게되어 이번 기회에 관련 자료를 정리하기로 했다. MongoDB가 왜 필요한지, 더 잘사용하기 위해서 무엇이 필요한지를 중심으로 처음 MongoDB를 사용할 때

kciter.so

 

 

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


build.gradle에 노란색 형광펜 친 것을 넣어준다. 

 

https://we1cometomeanings.tistory.com/43?category=953098 

 

#1_그레이들 프로젝트를 스프링부트 프로젝트로 변경하기

2019년에 발행된 책 '스프링부트와 AWS로 혼자 구현하는 웹서비스' 를 참고하여 공부한 내용을 기록합니다. 새 프로젝트 생성 후 build.gradle을 클릭한다. 그러면 자바 개발에 기초적인 설정만 되어

we1cometomeanings.tistory.com

위에 링크에 있는 build.gradle을  따라서 친 사람은 어차피 코드가 써져있을 것이다.

 

 

spring-boot-starter-data-jpa


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

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

 

h2


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

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

메모리에서 실행되기 때문에 애플리케이션을 재시작할때 마다 초기화된다는 점을 이용하여 테스트 용도로 많이 사용

JPA의 테스트, 로컬 환경에서의 구동에서 사용 예정

 

 

domain 패키지를 만들어준다. 말그대로 도메인을 담을 패키지로, 도메인이란 게시글,댓글,회원,정산,결제 등 소프트웨어에 대한 요구사항 혹은 문제영역을 말한다.

 

domain 하위에는 posts 패키지를 만들고, Posts 클래스를 만들어준다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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;
    }
    
}
cs

@Entity

 

- 테이블과 링크될 클래스임을 나타낸다.

- 기본값으로 클래스의 카멜케이스 이름을 언더스코어 네이밍으로 테이블 이름을 매칭한다.

ex) SalesManager.java->sales_manager table

 

@Id

 

- 해당 테이블의 PK필드를 나타낸다.(오라클의 Primary Key를 의미) 

 

@Generated Value

 

- PK 생성규칙을 나타낸다.

 

@Column

 

- 테이블의 칼럼을 나타내며 굳이 선언하지 않더라도 해당 클래스의 필드는 모두 칼럼이 된다. 

- 사용하는 이유는 기본값 이외에 추가로 변경이 필요한 옵션이 있으면 사용한다.

 

롬복 라이브러리의 어노테이션 


@NoArgsConstructor

 

- 기본 생성자 자동 추가

- public Posts() {}와 같은 효과

 

@Getter

 

- 클래스 내 모든 필드의 Getter메소드를 자동생성

 

@Builder

 

- 해당 클래스의 빌더 패턴 클래스를 생성

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

 

서비스 초기 구축 단계에서는 테이블 설계(여기선 Entity 설계)가 빈번하게 변경되는데, 이때 롬복의 어노테이션들은 코드 변경량을 최소화 시켜주기 때문에 적극적으로 사용된다. 

 

Posts 클래스에 특이점이 있는데, Setter 메소드가 없다.

getter/setter를 무작정 사용하면 해당 클래스의 인스턴스 값들이 언제 어디서 변해야 하는지 코드상으로 명확하게 구분할 수 없어 차후 기능 변경시 복잡해진다.

그래서 Entity 클래스에서는 절대 Setter 메소드를 만들지 않는다

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

 

예를 들어 주문 취소 메소드를 만든다고 가정해보자.

 

<잘못된 사용 예>

 

public class Order{

    public void static setStatus(boolean status){

                   this.status=status;

    }

}

 

public void 주문서비스의_취소이벤트(){

         order.setStatus(false);

}

 

<올바른 사용 예>

 

public class Order{

    public void cancelOrder(){

          this.status=false;

   }

}

 

public void 주문서비스의_취소이벤트(){

       order.cancelOrder();

}

 

 

그렇다면 Setter가 없는 상황에서 어떻게 값을 채워 DB에 삽입해야할까?

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

우리는 생성자 대신에 @Builder를 통해 제공되는 빌더 클래스를 사용한다. 생성자나 빌더나 생성 시점에 값을 채워주는 역할은 똑같다.

다만 생성자의 경우 지금 채워야 할 필드가 무엇인지 명확히 지정할 수 없다.

 

<생성자를 쓸 때>

 

public Example(String a,String b){

      this.a=a;

      this.b=b;

}

 

<빌더를 쓸 때>

 

Example.builder()

     .a(a)

     .b(b)

     .build();

 

Posts 클래스로 Database를 접근하게 해줄 JpaRepository를 생성해준다. 

 

 

1
2
3
4
5
import org.springframework.data.jpa.repository.JpaRepository;
 
public interface PostsRepository extends JpaRepository<Posts,Long>{
}
 
cs

 

보통 ibatis나 MyBatis등에서 Dao라고 불리는 DB Layer접근자이다. JPA에선 Repository라고 부르며 인터페이스로 생성한다. 단순히 인터페이스를 생성후, JpaRepository<Entity 클래스,PK 타입>를 상속하면 기본적인 CRUD 메소드가 자동으로 생성된다.

 

+) Dao란 Data Access Object의 약자로 간단히 Database의 data에 접근을 위한 객체

 

@Repository를 추가할 필요도 없다. 주의할 점은 Entity 클래스와 기본 Entity Repository는 함께 위치해야한다는 점이다. 둘은 아주 밀접한 관계이고, Entity클래스는 기본 repository없이는 제대로 역할을 할 수가 없다.

 

+)ibatis -> SQL에 기반한 데이터베이스와 자바, 닷넷(.NET), 루비(Ruby) 등을 연결시켜 주는 역할을 하는 영속성 프레임워크(Persistence Framework)이다.

+)Mybatis -> Mybatis는 자바 오브젝트와 SQL사이의 자동 매핑 기능을 지원하는 ORM(Object relational Mapping)프레임워크이다.

 

cf) dao와 Repository의 차이점

 

https://bperhaps.tistory.com/entry/Repository%EC%99%80-Dao%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90

 

Repository와 Dao의 차이점.

Repository와 Dao의 차이점에 대한 논쟁은 이전부터 끝없이 진행되어 왔다. 이번 포스팅에서는 Repository와 Dao의 차이에 대한 나의 생각을 논해보록한다. 필자가 생각하기에 Dao와 Repository의 차이점을

bperhaps.tistory.com

 

둘의 차이점이 너무 어렵다. 좀더 공부를 한 뒤에 읽어봐야겠다.!

728x90
반응형

댓글