본문 바로가기

BackEnd/Spring Boot

[스프링 부트 쇼핑몰 프로젝트 with JPA] Spring Data JPA 1(ORM, 상품 엔티티, 영속성)

728x90
반응형

1. JPA

 (1) JPA(Jave Persistence API’)는 자바 ORM 기술에 대한 API 표준
 (2) ORM이란 ‘Object Relational Mapping’의 약자로 객체(java)와 관계형 데이터베이스(SQL) 매핑

   ▷ JPA는 ORM의 기술 표준 명세로 자바에서 제공하는 API

   ▷ JPA는 인터페이스고 구현한 가장 대표적인 오픈소스가 Hibernate(하이버네이트)

 

◎ JPA 장점

 (1) 특정 데이터베이스에 종속되지 않음

   ▷ 처음 선택한 데이터베이스를 변경하기 어렵지만 JPA는 추상화한 데이터 접근 계층을 제공

   ▷ 설정 파일에 어떤 데이터베이스를 사용하는지 알려주면 얼마든지 데이터베이스를 변경
 (2) 객체지향적으로 설계 가능

   ▷ JPA를 사용하면 데이터베이스 설계 중심 패러다임에서 객체지향적으로 설계 가능
 (3) 유지보수 유리 및 생산성 향상

   ▷ 테이블에 새로운 컬럼이 추가되었을 경우, 해당 테이블 컬럼을 사용하는 DTO 클래스 필드 모두 변경해야함

   ▷ JPA에서는 테이블과 매핑된 클래스에 필드만 추가한다면 쉽게 관리 가능

   ▷ SQL문을 직접 작성하지 않고 객체를 사용하여 동작하므로 유지보수가 좋고 재사용성 증가

 

◎ JPA 단점

 (1) 복잡한 쿼리 처리

   ▷ DB의 View, 프로시저 이용해서 처리 가능(단점 보완), JPQL
 (2) 성능 저하 위험

   ▷ 의도하지 않은 쿼리가 많이 만들어지면서 성능 저하됨

   ▷ 객체간 매핑 설계를 잘못했을 때 성능 저하 발생
 (3) 학습 시간

   ▷ JPA를 제대로 사용하기 위해서는 내용이 많아 시간이 오래 걸림

   ▷ 관계형 데이터베이스를 충분히 알아야 JPA를 잘 사용할 수 있음

 

 

◎ JPA 동작 방식


◎ 엔티티(Entity) : 데이터베이스의 테이블에 대응하는 클래스
   ▷ @Entity가 붙은 클래스는 JPA에서 관리하며 엔티티라고 함
   ▷ 데이터베이스에 item 테이블을 만들고 Item.java 클래스를 만들어 @Entity 어노테이션을 붙이면 이 클래스가 엔티티가 됨
   ▷ 클래스 자체나 생성한 인스턴스도 엔티티라고 함

◎ 엔티티 매니저 팩토리(Entity Manager Factory) : 엔티티 매니저 인스턴스를 관리하는 주체
   ▷ 애플리케이션 실행 시 한 개만 만들어지며 사용자로부터 요청이 오면 엔티티 매니저로 팩토리로부터 엔티티 매니저 생성

◎ 엔티티 매니저(Entity Manager) : 영속성 컨텍스트에 접근하여 엔티티에 대한 데이터베이스 작업을 제공
   ▷ 데이터베이스 커넥션을 사용해 데이터베이스에 접근

 

 

◎ 엔티티 생명주기의 세부 내용


◎ find() 메소드 : 영속성 컨텍스트에서 엔티티를 검색하고 영속성 컨텍스트에 없을 경우 데이터베이스에서 데이터를 찾아 영속성 컨텍스트에 저장
◎ persist() 메소드 : 엔티티를 영속성 컨텍스트에 저장
◎ remove() 메소드 : 엔티티 클래스를 영속성 컨텍스트에서 삭제
◎ flush() 메소드 : 영속성 컨텍스트에 저장된 내용을 데이터베이스에 반영

 

 

◎ JPA 동작 방식


① 영속성 컨텍스트에 저장할 상품 엔티티 하나 생성, new 키워드를 통해 생성했으므로 영속성 컨텍스트와 관련이 없음
② 엔티티 매니저 팩토리로부터 엔티티 매니저를 생성
③ 엔티티 매니저는 데이터 변경 시 데이터 무결성을 위해 반드시 트랜잭션 시작해야 함
     트랜잭션도 데이터베이스의 트랜잭션과 같은 의미
④ 생성한 상품 엔티티가 영속성 컨텍스트에 저장된 상태, 데이터베이스에 INSERT SQL을 보내지 않은 단계
⑤ 트랜잭션을 데이터베이스에 반영, 영속성 컨텍스트에 저장된 상품 정보가 데이터베이스 INSERT 되면서 반영
⑥, ⑦ 엔티티 매니저와 엔티티 매니저 팩토리의 close() 메소드를 호출해 사용한 자원을 반환

 

◎ 영속성 컨텍스트 사용 시 이점


▷ 애플리케이션과 데이터베이스 사이에 영속성 컨텍스트라는 중간 계층을 만들었기 때문에 영속성을 사용
 중간 계층은 버퍼링, 캐싱 등을 사용할 수 있는 장점이 있음

◎ 1차 캐시
   ▷ 영속성 컨텍스트에 Map<KEY, VALUE>로 저장. entityManager.find() 메소드 호출 시 영속성 컨텍스트의 1차 캐시 조회 
   ▷ 엔티티가 존재할 경우 해당 엔티티를 반환, 없으면 데이터베이스에서 조회 후 1차 캐시에 저장 및 반환

◎ 동일성 보장
   ▷ 하나의 트랜잭션에서  같은 키값으로 영속성 컨텍스트 조회 시 같은 엔티티 조회 보장 (1차 캐시)


◎ 트랜잭션을 지원하는 쓰기 지연
   ▷ entityManager.persist()를 호출하면 1차 캐시에 저장되는 것과 동시에 쓰기 지연 SQL 저장소에 SQL문이 저장됨
   ▷ 쓰기 지연 SQL 저장소에 SQL을 쌓아두고 트랜 잭션 커밋 시점에 저장된 SQL 문 flush하여 데이터베이스 반영

 변경 감지
   ▷ 1차 캐시에 데이터베이스에서 처음 불러온 엔티티의 스냅샷 저장
   ▷ 커밋 시점에 변경 내용을 자동 반영. 즉, update문을 호출하지 않아도 됨.

 

2. 새 프로젝트 생성(shop) 후 동일하게 generate


▷ Thymeleaf : 서버에 가공한 데이터를 뷰에 보여주기 위한 템플릿 엔진으로 타임리프 의존성을 추가
▷ Spring Data JPA : Spring Data JPA : 2.1절에서 살펴보았던 JPA를 쉽게 구현할 수 있도록 도와주는 모듈
▷ MySQL Driver : 프로젝트에서 사용할 데이터베이스는 MySQL임. MySQL 데이터베이스를 사용하기 위해 의존성 추가
▷ H2 Database : H2 Database는 자바 기반의 관계형 데이터베이스로 매우 가볍고 빠른 데이터베이스
   ▶ 디스크 기반의 데이터 저장뿐만 아니라 메모리 내에 데이터를 저장하는 인메모리 데이터베이스 기능 지원
   ▶ 데이터를 영구적으로 저장하는 데 권장되는 데이터베이스는 아니지만 위의 장점들 때문에 테스트용으로 사용

◎ 생성된 알집 파일을 SpringBootWork에 추가

 

◎ application.properties 설정

# 애플리케이션 포트 설정
server.port = 8080

#MySQL 연결 설정
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shop?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=1234

#실행되는 쿼리 콘솔 출력
spring.jpa.properties.hibernate.show_sql=true

#콘솔창에 출력되는 쿼리를 가독성이 좋게 포맷팅
spring.jpa.properties.hibernate.format_sql=true

#쿼리에 물음표로 출력되는 바인드 파라미터 출력
logging.level.org.hibernate.type.descriptor.sql=trace

spring.jpa.hibernate.ddl-auto=create
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect

 

◎ 데이터베이스 초기화 전략 DDL AUTO 옵션

NO 문법 특징
1 none 사용하지 않음
2 create 기존 테이블 삭제 후 테이블 생성
3 create-drop 기존 테이블 삭제 후 테이블 생성. 종료 시점에 테이블 삭제
4 update 변경된 스키마 적용
5 validate 엔티티와 테이블 정상 매핑 확인

 

3. 상품 엔티티 설계

   ▷ com.shop.constant 패키지 및 ItemSellStatus 클래스 생성

   ▷ com.shop.entity 패키지 및 Item 클래스 생성


1. ItemSellStatus 클래스 수정(enum 타입의 클래스)

package com.shop.constant;

public enum ItemSellStatus {
    SELL, SOLD_OUT
}


2. Item 클래스 수정

package com.shop.entity;

import com.shop.constant.ItemSellStatus;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.time.LocalDateTime;

@Getter
@Setter
@ToString
public class Item {
    private Long id;                        // 상품 코드
    private String itemNm;                  // 상품명
    private int price;                      // 가격
    private int stockNumber;                // 재고 수량
    private String itemDetail;              // 상품 상세 설명
    private ItemSellStatus itemSellStatus;  // 상품 판매 상태
    private LocalDateTime regTime;          // 등록 시간
    private LocalDateTime updateTiem;       // 수정 시간
}

 

◎ 엔티티 매핑 관련 어노테이션

 

◎ @Column 어노테이션 추가 속성

 

기본키 : 중복(x), 널 값 허용하지 않음

유니크 : 중복(x), 널 값 허용

 

◎ @GeneratedValue 어노테이션을 통한 기본키 생성 전략

 

 

◎ Item 클래스 수정

   ▷ 상품 클래스 엔티티 매핑_Ver02

package com.shop.entity;

import com.shop.constant.ItemSellStatus;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import javax.persistence.*;
import java.time.LocalDateTime;

@Entity
@Table(name = "item")
@Getter
@Setter
@ToString
public class Item {

    @Id
    @Column(name = "item_id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;                        // 상품 코드

    @Column(nullable = false, length = 50)
    private String itemNm;                  // 상품명

    @Column(name = "price", nullable = false)
    private int price;                      // 가격

    @Column(nullable = false)
    private int stockNumber;                // 재고 수량

    @Lob
    @Column(nullable = false)
    private String itemDetail;              // 상품 상세 설명

    @Enumerated(EnumType.STRING)
    private ItemSellStatus itemSellStatus;  // 상품 판매 상태

    private LocalDateTime regTime;          // 등록 시간

    private LocalDateTime updateTime;       // 수정 시간
}


콘솔 창에 아래와 같이 테이블이 생성된 것을 확인할 수 있습니다.



▷ MySQL에 table이 생성되는 것을 확인할 수 있습니다.


◎ setting → file encodings → 모두 UTF-8로 변경

 

스프링 부트는 어노테이션을 이용해서 코드들을 확실하게 줄일 수 있었습니다.

 

또한 어노테이션을 자동으로 import를 할 수 있었습니다.

 

클래스에서 Table 이름과 열 이름 및 조건들을 입력해서 DB에 테이블을 만들 수도 있었습니다.

 

이전에 했던 스프링에 비해서 훨씬 코드가 간결해지는 것이 신기했어요!!

 

아마 스프링 부트만 사용하다보면 스프링은 사용하기 어렵겠죠?,,ㅎㅎ

 

그래도 모든 언어를 잘하는 개발자가 되고싶네요!!

 

많은 분들의 피드백은 언제나 환영합니다!  많은 댓글 부탁드려요~~

 

 

728x90
반응형