본문 바로가기

WEB/Spring

[스프링 부트와 AWS로 혼자 구현하는 웹 서비스] JPA_도메인

JPA 소개

패러다임 불일치

  • 객체 지향 프로그램과 관계형 데이터 베이스의 “패러다임 불일치”
    • 객체 지향 프로그래밍 = 메시지를 기반으로 기능과 속성을 한 곳에서 관리
    • 관계형 데이터베이스 = 어떻게 데이터를 저장할지
  • 객체 지향의 부모 관계 자식의 관계를 관계 데이터 베이스로 구현하기 없다. → 개발이 데이터 모델링에만 집중하게 된다는 단점
  • 해결 방법 = JPA = 객체 중심으로 개발 가능

[ Spring Data JPA ]

  • 개념
    • JPA = 인터페이스로서 자바 표준 명세서이다.
    • 인터페이스인 JPA를 사용하기 위해서 구현체가 필요하다. (ex) Hibernate, Eclipse Link
    • 하지만 스프링에서 JPA를 사용할 때 이 구현체들을 직접 다루지 않음
    • 구현체를 좀 더 쉽게 사용하고자 추상화 시킴(= Spring Data JPA)
  • 관계
    • JPA ← Hibernate ← Spring Data JPA
  • Spring Data JPA 등장 이유 2가지
    • (1) Hibernate 외에 다른 구현체로 쉽게 교체 가능
    • (2) 관계형 데이터베이스 외에 다른 저장소로 쉽게 교체 가능
      • 기본적인 CRUD 인터페이스가 같음

프로젝트에 Spring Data Jpa 적용

[ domain ]

= 게시글 , 댓글, 회원, 정산, 결제 등 소프트웨어에 대한 요구 사항 혹은 문제 영역

  • 이전과 다른점
    • 이전에 Mybatis와 같은 쿼리 매퍼를 사용 → dao 패키지(xml에 쿼리를 담고 클래스는 오로지 쿼리 결과만 담음)
    • 이 역할을 “도메인 클래스"라고 불리는 곳에서 해결

[참고]

참고 : 어노테이션 순서 → 중요한 순서 주요 어노테이션을 클래스에 가깝게 두기

ex) Entity어노테이션은 JPA의 어노테이션, Getter과 NoArgsConstruct는 롬복의 어노테이션이다.

→ 롬복은 코드를 단순화 시켜주지만 필수 어노테이션은 아니다.

→ 필수 어노테이션 Entity를 클래스에 가깝게 두고 롬복은 그 위로 두었다.

  • 장점 = 새언어 전환으로 롬복이 더 이상 필요 없을 경우 쉽게 삭제 가능

[ 어노테이션 ]

@Entity

  • = 테이블과 링크될 클래스

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

ex) SalesManager.java → sales_manager table

@Id

  • 해당 테이블의 PK 필드를 나타낸다.

@GenerateValue

  • = PK의 생성 규칙을 나타낸다.
  • ex) Generatio Type.IDENTITY ⇒ auto_increment

@Column

  • = 테이블의 칼럼을 나타낸다.
  • 굳이 선언하지 않더라도 해당 클래스의 필드는 모두 칼럼 테이블이 된다.
  • 사용 이유
    • 기본값 외에 추가로 변경이 필요한 옵션이 있으면 사용
    • ex) 문자열의 경우 VARCHAR(255)가 기본값인데 사이즈를 500으로 늘리고 싶거나
      • 타입을 TEXT로 변경하고 싶을 경우

[참고]

  • 웬만하면 PK는 Long타입의 Auto_increment를 추천
    • MySql 기준으로 이렇게 하면 bigint 타입이 된다.
    • 주민등록번호와 같이 비즈니스상 유니크 키나 여러 키를 조합한 복합키로 PK를 잡을 경우 난감한 상황이 종종 발생한다.
      • (1) FK를 맺을 때 다른 테이블에서 복합키 전부를 갖고 있거나 중간 테이블을 하나 더 둬야하는 상황 발생
      • 인덱스에 좋은 영향을 끼치지 못한다.
      • 유니크한 조건이 변경될 경우 PK 전체를 수정해야 하는 일이 발생
    • 주민등록번호, 복합키 등은 유니크 키로 별도로 추가하는 것을 추천

@NoArgsConstructor

  • = 기본 생성자 자동 추가
  • public Posts() {} 와 같은 효과

@Getter

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

@Builder

  • = 해당 클래스의 빌더 패턴 클래스 생성
  • 생성자 상단에 선언 시 생성자에 포함된 필드만 빌더에 포함

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

 

DB에 삽입하는 문제에 대해서

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

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

기본적인 전제

(1) 생성자를 통해 최종값을 채운 후 DB에 삽입

(2) 값 변경이 필요한 경우 해당 이벤트에 맞는 public 메소드를 호출하여 변경하는 것

@Builder

  • 생성자 대신에 @Builder를 통해 제공되는 빌더 클래스를 사용
  • 생성 시점에 값을 채워준다(생성자나 빌더나)
    • 다만, 생성자의 경우 지금 채워야 할 필드가 무엇인지 명확히 지정할 수 없음 <같은 타입이므로 순서를 변경해서 저장할 수 있는데 순서 변경으로 인해 문제 생긴 경우 코드를 실행하기 전까지 모른다>
public Exam(String a, Sting b) { this.a = a; this.b = b; } 

-> Exam(b, a);
  • 하지만 빌더패턴은 어느 필드에 어떤 값을 채워야할지 명확하게 인지 가능
Example.builder() 
     .a(a) 
     .b(b) 
     .build();

 

이 글은 "스프링 부트와 AWS로 혼자 구현하는 웹 서비스"(이동욱) 를 읽고 작성하였습니다. (3장)