JPA, Hibernate, 그리고 Spring Data JPA의 차이점
[JPA는 기술 명세]
JPA는 Java Persistence API의 약자로, 자바 어플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스이다. 여기서 중요하게 여겨야 할 부분은, JPA는 말 그대로 인터페이스라는 점이다. JPA는 특정 기능을 하는 라이브러리가 아니다. 마치 일반적인 백엔드 API가 클라이언트가 어떻게 서버를 사용해야 하는지를 정의한 것처럼, JPA 역시 자바 어플리케이션에서 관계형 데이터베이스를 어떻게 사용해야 하는지를 정의하는 한 방법일 뿐이다.
JPA는 단순히 명세이기 때문에 구현이 없다. JPA를 정의한 javax.persistence 패키지의 대부분은 interface, enum, Exception, 그리고 각종 Annotation으로 이루어져 있다. 예를 들어, JPA의 핵심이 되는 EntityManager는 아래와 같이 javax.persistence.EntityManager 라는 파일에 interface로 정의되어 있다.
package javax.persistence;
import ...
public interface EntityManager {
public void persist(Object entity);
public <T> T merge(T entity);
public void remove(Object entity);
public <T> T find(Class<T> entityClass, Object primaryKey);
// More interface methods...
}
Spring Data JPA를 사용하지 않는 JPA 사용 예시
@Repository
@RequiredArgsConstructor
public class OrderRepository {
private final EntityManager em;
public void save(Order order){
em.persist(order);
}
public Order findOne(Long id){
return em.find(Order.class, id);
}
public List<Order> findAll() {
return em.createQuery("select o from Order o", Order.class)
.getResultList();
}
public List<Order> findAllWithItem() {
return em.createQuery(
"select distinct o from Order o" +
" join fetch o.member m" +
" join fetch o.delivery d" +
" join fetch o.orderItems oi" +
" join fetch oi.item i", Order.class)
.getResultList();
}
}
[Hibernate는 JPA의 구현체]
Hibernate는 JPA라는 명세의 구현체이다. 즉, 위에서 언급한 javax.persistence.EntityManager와 같은 인터페이스를 직접 구현한 라이브러리이다. JPA와 Hibernate는 마치 자바의 interface와 해당 interface를 구현한 class와 같은 관계이다.
JPA의 핵심인 EntityManagerFactory, EntityManager, EntityTransaction을 Hibernate에서는 각각 SessionFactory, Session, Transaction으로 상속받고 각각 Impl로 구현하고 있음을 확인할 수 있다.
[Spring Data JPA는 JPA를 쓰기 편하게 만들어 놓은 모듈]
Repository가 바로 Spring Data JPA의 핵심
Spring Data JPA는 Spring에서 제공하는 모듈 중 하나로, 개발자가 JPA를 더 쉽고 편하게 사용할 수 있도록 도와준다. 이는 JPA를 한 단계 추상화시킨 Repository라는 인터페이스를 제공함으로써 이루어진다. 사용자가 Repository 인터페이스에 정해진 규칙대로 메소드를 입력하면, Spring이 알아서 해당 메소드 이름에 적합한 쿼리를 날리는 구현체를 만들어서 Bean으로 등록해준다.
Spring Data JPA가 JPA를 추상화했다는 말은, Spring Data JPA의 Repository의 구현에서 JPA를 사용하고 있다는 것이다. 예를 들어, Repository 인터페이스의 기본 구현체인 SimpleJpaRepository의 코드를 보면 아래와 같이 내부적으로 EntityManager을 사용하고 있는 것을 볼 수 있다.
# 참고 사이트
https://suhwan.dev/2019/02/24/jpa-vs-hibernate-vs-spring-data-jpa/
https://velog.io/@codren/Spring-DB-2
https://velog.io/@evelyn82ny/JPA-vs-Spring-Data-JPA 중요!!
[상품 Repository 설계]
Spring Data JPA에서는 Data Access Object역할을 하는 Repository 인터페이스를 설계 후 사용하는 것 만으로도 엔티티 매니저를 직접 이용하지 않아도 됨
ㅇ JpaRepository를 상속받는 ItemRepository 작성
: JpaRepository는 2개의 제네릭 타입을 사용, 첫 번째: 엔티티 타입 클래스/ 두 번째: 기본키 타입
: JpaRepository 인터페이스는 기본적인 CRUD 및 페이징 처리를 위한 메소드 정의
package com.jeong.shop.repository;
import com.jeong.shop.entity.ItemEntity;
import org.springframework.data.jpa.repository.JpaRepository;
// JpaRepository에는 기본적인 CRUD 및 페이징 처리를 위한 메소드 정의
public interface ItemRepository extends JpaRepository<ItemEntity, Long> {
}
ㅇ h2 데이터베이스를 사용한 테스트 케이스 작성
* H2 데이터베이스는 메모리에 데이터를 저장하는 인메모리 데이터베이스 기능을 제공
애플리케이션이 종료되면 데이터베이스에 저장된 데이터 삭제, 또한 가볍고 빠르기 때문에 개발할 때 테스트용으로 많이 사용
package com.jeong.shop.repository;
import com.jeong.shop.constant.ItemSellStatus;
import com.jeong.shop.entity.ItemEntity;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import java.time.LocalDateTime;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest // 통합 테스트를 위해 스프링 부트에서 제공하는 어노테이션, 실제 어플리케이션을 구동할 때처럼 모든 Bean을 IoC 컨테이너에 등록
@TestPropertySource(locations="classpath:application-test.properties") // 설정 파일 application-test.properties에 우선순위 부여 : Test DB로 H2를 사용
class ItemRepositoryTest {
@Autowired // itemRepository를 사용하기 위하여 @Autowired 어노테이션을 이용하여 Bean 주입
ItemRepository itemRepository;
@Test // 테스트할 대상 지정 : 테스트할 메소드 위에 선언
@DisplayName("상품 저장 테스트") // Junit5에 추가된 어노테이션으로 테스트 코드 실행 시 @DisplayName에 지정한 테스트명 노출
public void createItemTest() {
ItemEntity item = new ItemEntity();
item.setItemName("테스트 상품");
item.setPrice(10000);
item.setStockNumber(100);
item.setItemDetail("테스트 상품 상세 설명");
item.setItemSellStatus(ItemSellStatus.SELL);
item.setRegTime(LocalDateTime.now());
item.setUpdateTime(LocalDateTime.now());
ItemEntity savedItem = itemRepository.save(item); // itemRepository가 상속받은 JpaRepository(CrudRepository) 인터페이스의 save 메소드 동작
System.out.println(savedItem.toString());
}
}
1. 관련 어노테이션
1) @SpringBootTest
: 통합 테스트를 위해 스프링 부트에서 제공하는 어노테이션, 실제 어플리케이션을 구동할 때처럼 모든 Bean을 IoC 컨테이너에 등록
2) @TestPropertySource(locations="classpath:application-test.properties")
: 테스크 코드 실행 시 application.properties에 설정해둔 값보다. application-test.properties에 같은 설정이 있다면 더 높은 우선순위 부여 : Test DB로 H2를 사용
3) @Autowired
: itemRepository를 사용하기 위하여 해당 어노테이션을 이용하여 Bean 주입
4) @Test
: 테스트할 메소드 위에 선언하여 해당 메소드를 테스트 대상으로 지정
5) @DisplayName(“ “)
: Junit5에 추가된 어노테이션으로 테스트 코드 실행 시 @DisplayName에 지정한 테스트명 노출
2. Repository 의 하위 메소드 사용
ItemEntity savedItem = itemRepository.save(item);
: itemRepository가 상속받은 JpaRepository(CrudRepository) 인터페이스의 save 메소드 동작
* JpaRepository의 상속 구조
: JpaRepository à PagingAndSortRepository à CrudRepository à Repository
: 일반적인 기능만을 사용할 때는 CrudRepository를 사용하는 것이 좋고, 모든 JPA관련 기능을 사용하고 싶을 때는 JpaRepository를 이용하며, 특별한 경우 아닌 이상 JpaRepository를 사용한다.
# 참고사이트
JpaRepository 인터페이스https://velog.io/@hermaeus/7.JpaRepository-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4
모르는 추가 개념 정리 |
* Bean * IoC 컨테이너 |
스프링 부트 쇼핑몰 프로젝트 with JPA
날짜 | 진행내용 | 페이지 | 난이도 | 참고사항 |
22.11.29 | 1. application.properties 설정 오류 해결 2. 상품 Repository 설계 및 테스트 코드 작성 |
p80~85 | ㅇ 파일 옵션 학습 필요 : application.properties 옵션들 / build.gradle 옵션들 ㅇ 정말 말도 안되는 오류지만 해결해서 뿌듯!! |
|
22.11.30 | 1. 상품 Repository 및 Test코드 관련 기본 개념 및 어노테이션 학습 | p80~85 | ㅇ 개념 이해 필요 용어 : Bean, IoC 컨테이너 ㅇ JpaRepository 상속 구조 및 인터페이스 구조 추가 학습 필요 |
추후 공부 계획(12.01 ~ 12.04)
1. 쿼리 메소드 및 @Query어노테이션, Querydsl 학습
2. Bean과 IoC 컨테이너 개념 학습
3. Thymeleaf 학습
'도젼~ > [22.11.18~] 스프링 부트 쇼핑몰 프로젝트' 카테고리의 다른 글
20221205~06 TIL (0) | 2022.12.07 |
---|---|
20221201 TIL (0) | 2022.12.02 |
20221127 TIL (0) | 2022.11.27 |
20221123 TIL (0) | 2022.11.24 |
20221120 TIL (0) | 2022.11.20 |