[스프링 부트 쇼핑몰 프로젝트 with JPA] Spring Data JPA 1(ORM, 상품 엔티티, 영속성)
bobo122023. 4. 4. 07:50
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에 테이블을 만들 수도 있었습니다.