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장)
'WEB > Spring' 카테고리의 다른 글
스프링 컨테이너와 스프링 빈 (0) | 2022.08.18 |
---|---|
AppConfig와 DI (0) | 2022.08.16 |
웹 애플리케이션의 이해 - WAS와 서블릿 (0) | 2022.08.13 |
객체 지향과 스프링(다형성과 SOLID) (0) | 2022.08.12 |
[🔐 스프링 시큐리티] 스프링 시큐리티 용어와 흐름 (2) | 2022.08.11 |