-
[Spring Boot] JPA (2/4) : JPA 기본 개념서버개발/spring-boot 2020. 1. 30. 14:52
목적
JPA 의 탄생 배경부터 특징, 그리고 JPA를 이해하기 위한 ORM 표준등 관련된 용어의 개념에 대해 정리한다.
JPA 란
JPA(Java Persistence API)는 ORM(Object-Relation Mapping) 전문가가 참여한 EJB 3.0(Enterprise Java Beans) 스펙 작업에서 기존 EJB ORM 표준으로 사용되던 엔티티빈(Entity Bean) 을 대체하여 나온 ORM 표준이다. 기존 엔티티빈이 EJB 컨테이너에 의존하던것에 비해 POJO 방식 프레임워크로 개발되었으며, 이로인해 Java EE 뿐 아니라 JAVA SE 에서도 사용 가능하며 활용도가 높다.
*POJO : https://itewbm.tistory.com/entry/POJOPlain-Old-Java-Object
JPA 역사
EJB 3.0 이전까지 ORM 표준 기술은 엔티티빈(Entity Bean) 이었다. 여기서 EJB 는 J2E(Java Platform Enterprise Edition)에서 제공하는 기능 중 분산 어플리케이션을 지원하는 컴포넌트 기반의 객체이다. 등장 이전에 분산 환경의 어플리케이션 개발시 개발자가 고려할 사항은 비즈니스 로직 뿐 아닌 트랜잭션, 동시접속, 보안 등을 고려해야 했다. EJB는 JBoss 와 같은 EJB Container 에 올려서 서비스가 된다(JBOSS : J2E 표준을 모두 구현한 WAS(추가 확인 필요)).
엔티티빈을 통해 JDBC를 직접 제어하지 않아도 되었지만 복잡한 사용성과 컨테이너상에서 동작해야 하기 때문에 무거움, 개발시점의 빌드/테스트 절차의 불편함 으로 인해 실제 어플리케이션에 적용하기 어려운 기술이었다. 특히 ORM만을 사용하기 위해 EJB의 모든 기능을 가져오는것은 쓸데없는 서버 스펙만 향상시키는 원인이었고 그만큼의 편의성도 없다는 것이 일반적인 평가였으며 매우 저조한 사용률을 보이게 된다.
JPA는 앞서 말한 대로 EJB 3.0 스펙 작업에서 EJB의 시장성 없는 기술을 포기하고 POJO 기반의 경량 엔터프라이즈 기술로 방향을 잡아 만들어졌다. POJO 기반 프레임워크 이기 때문에 가볍고 빠르며 활용도가 높다. JPA는 스펙이 분리된 후 이름을 엔티티빈에서 JPA로 변경했다(이는 EJB 환경에 종속적이지 않은 독립적인 퍼시스턴스 기술로 만들어졌기 떄문이라는 말이 있음).
그리고 EJB 파트는 독립 스펙으로 분리되었으며 이로인해 개발자는 엔티티빈을 필수로 사용할 필요가 없어졌다. 퍼시스턴스 프레임워크(Persistence Framework)와 엔진(벤더)를 자유롭게 선택이 가능해졌다.
용어 설명
ORM(Object Relational Mapping)
관계형 데이터베이스의 데이터를 자동으로 매핑해 주는 것을 의미한다. 데이터 모델과 OOP의 불일치를 해결하기 위해 등장했으며, SQL의 절차적이고 순차적인 접근이 아닌 객체지향적인 접근을 가능하게 한다.
ORM 프레임워크로는 이 페이지에서 다루는 JPA를 비롯해 Hibernate 가 대표적이며, 장단점은 다음과 같다.
장점
- 객체지향적인 코드 작성이 가능하다.
- 직관성
- 비즈니스 로직에 집중
- 재사용성 및 유지보수 편의가 증가한다
- DBMS 밴더에 독립적
- SQL 자동 생성
- 데이터 모델과 객체간의 차이 해결
- DBMS 밴더에 독립적
- Java 기능/특성 활용이 가능하다.
- 매핑된 데이터는 자바 클래스 이기 때문에 클래스의 기능을 활용할 수 있다.
- ex) 상속, new, equal&hashCode 등의 언어 특성, 편의기능
- 매핑된 데이터는 자바 클래스 이기 때문에 클래스의 기능을 활용할 수 있다.
단점
- 데이터 모델의 복잡도에 비례해 난이도가 증가한다.
- 사용의 편의성으로 인해 무분별한 데이터 모델링을 하게 될 수 있다.
- 성능 저하, 일관성, 정합성
- 대형 쿼리 구현시 별도 튜닝이 필요한 경우가 종종 발생한다.
- 순수 ORM 프레임워크에서 제공하는 기능의 한계
- DBMS 고유 기능을 활용하기 어렵다.
- 경우에 따라 ERD 테이블 개수보다 더 많은 엔티티 클래스가 만들어 진다.
- 자바의 OOP 관점 설계로 인한 부작용
Persistence(영속성)
데이터를 생성한 프로그램이 종료되더라도 사라지지 않는 데이터의 특성을 말한다. 즉, 메모리 상의 데이터를 파일시스템, RDB등을 활용해 영구적으로 저장하는것을 영속성을 부여한다 라고 말할 수 있다.
기본적으로 어플리케이션에서 데이터베이스에 데이터를 저장하는 방법은 다음과 같은 방법이 있다.
- JDBC
- Spring JDBC (ex. jdbcTemplate)
- Persistence Framework (ex. JPA, Hibernate, Mybatis)
JPA에서 영속성은 영속성 컨텍스트에 접근하는 인터페이스인 EntityManager 를 통해 엔티티의 영속성을 관리한다.
API 핵심 인터페이스
JPA에서 제공하는 핵심 인터페이스에 대한 개념과, 실제 사용 예시 등을 알아본다.
EntityManager
영속성 컨텍스트에 엔티티를 보관하고 관리한다.
- 영속성 컨텍스트
: 엔티티 매니저(session)를 생성 할 때 하나씩 만들어지며, DB와 어플리케이션 사이에 위치한다.- 프로세스
- 조회할 데이터(엔티티)가 영속성 컨텍스트에 존재하는지 확인
- 데이터가 없으면 쿼리를 생성
- 쿼리를 DB에 전송
- 결과값을 영속성 컨텍스트가 전달받음
- 전달받은 데이터를 엔티티로 저장
- 엔티티 인스턴스를 리턴
- 특징
- 재사용 : 동일 쿼리 재 요청시 영속성 컨텍스트에 있는 엔티티를 가져와 재사용한다.
- 쓰기 지연 : 복수의 쿼리를 여러번 구현 한 경우, flush(transaction commit)가 되는 순간 한꺼번에 처리한다.
- 지연 로딩 : 특정 엔티티의 데이터를 사용하는 시점에 조회(select)하여 DB 요청을 보낼 수 있다.
- 이와 반대로 즉시 로딩의 개념은 연관된 엔티티를 함께 조회(join) 하는 방식을 말한다.
- 1차 캐시 : 복수 조회에 대해 캐시 사용.
- 영속성 컨텍스트를 통해 데이터의 동일성을 보장한다.
- 참고
- 영속성 관리 : https://wckhg89.tistory.com/10
- 프로세스
@Service // 각 메소드 마다 트랜잭션을 걸어준다. // 시작점에 transaction.begin(); 끝점에 transaction.commit()이 달린다고 생각하자. @Transactional public class MemberServiceImpl implements MemberService { ... @Override public void putMember(Member newMember) { // newMember : 영속화 되지 않은 엔티티 // member : 영속 상태 엔티티(영속 컨텍스트에 의해서 관리된다.) Member member = memberRepository.getMember(newMember.getId()); // 영속 컨텍스트에 의해서 관리되기 때문에 값을 바꾸어주면 쿼리를 캐시한다. (쓰기 지연 SQL 저장소) // 메소드가 끝나면 transaction 이 끝나면서 session.flush()가 일어나면서 update 쿼리가 반영된다. member.update(newMember); } } 출처: https://wckhg89.tistory.com/10 [줌구의 개발일기]
Query
플랫폼 독립적인 객체지향 쿼리 언어를 사용하며, Query 인터페이스는 관계형 데이터베이스의 엔티티에 대한 쿼리를 만든다.
- 특징
- JPQL
: SQL문과 비슷하지만 데이터베이스의 테이블에 직접 연결되는 것이 아니라 JPA 엔티티에 대해 동작하게 된다.- JPQL 쿼리의 칼럼은 엔티티의 필드 이름을 사용한다.
- Query Creation 매카니즘
: JPA에서의 쿼리 생성 매카니즘. 일반적으로 쿼리 메소드(Query method) 방식을 가장 많이 사용한다. - 메타정보에 정의된 관계 정보를 이용하면 복잡한 Join 설정 등이 필요하지 않기 떄문에 훨씬 간결하다.
- JPQL
@Query(value = "SELECT u.pathName as pathName, DATE(u.date) as date, u.visitCount as visitCount " + "FROM UserStatistics u GROUP BY DATE(u.date), u.pathName, u.visitCount") List<UserStatisticsDateCount> findVisitCountGroupByDate(); 출처 : https://donnaknew.tistory.com/3
Query q1 = em.createQuery("SELECT c FROM Country c"); TypedQuery<Country> q2 = em.createQuery("SELECT c FROM Country c", Country.class); 출처 : https://www.objectdb.com/java/jpa/query/api
기본 사용법
Query 항목, 출처 - JPA reference 를 참조한다.
다음 페이지에서 사용법에 대해 중점적으로 다룰 예정.
출처
- JPA reference : https://docs.spring.io/spring-data/jpa/docs/1.10.1.RELEASE/reference/html/#jpa.sample-app.finders.strategies
- EJB 란 : https://wikim.tistory.com/12
- 지연 로딩과 프록시 : https://victorydntmd.tistory.com/210
- JPA 영속성 컨텍스트란 : https://lng1982.tistory.com/273
- ObjectDB JPA 페이지 : https://www.objectdb.com/java/jpa/persistence/store
'서버개발 > spring-boot' 카테고리의 다른 글
[Spring Boot] JPA (1/4) : SQL/NoSQL 차이점 (0) 2020.01.29 [Spring Boot] HTTP/HTTPS (1/2) : 개념 이해 (1) 2020.01.21 [Spring Boot] OAuth2 (1/2) : 개념 이해 (0) 2020.01.21 - 객체지향적인 코드 작성이 가능하다.