목차
- JPA가 등장한 이유
- JPA란?
- 왜 JPA를 사용해야 하는가?
- JPA 주의사항
- JPA의 중요한 기능
예제 코드: https://github.com/yeon-06/inflearnSpring/tree/master/jpa-ex1
1. JPA가 등장한 이유
현재 많은 웹과 앱에서 데이터베이스는 관계형 DB를 주로 사용하고 있다.
NoSQL과 RDB 중 어떤 것의 성능이 더 좋다고 판별하지는 못하고 필요에 따라 선택한다.
(NoSQL을 모른다면? -> https://yeonyeon.tistory.com/159)
아직까지는 중요한 정보를 RDB에 저장하는 추세이다.
그렇다면 RDB를 이용함으로써 생기는 단점이 뭐가 있을까?
- 항상 CRUD 또는 객체와 매핑시키기. 반복적인 코드
- 객체에서 필드 수정 시 SQL도 수정 필요
결국 SQL에 의존적인 개발이 된다.
애초에 OOP(객체 지향 프로그래밍)와 RDB는 생성 목적이 다르다보니 패러다임의 불일치 문제가 발생한다.
OOP는 추상화, 캡슐화, 정보 은닉, 상속, 다형성 등 시스템 복잡성 제어를 위한 다양한 기능을 제공하는데 이 기능들을 100% 이용하지는 못하게 된다.
일단 객체와 테이블의 차이점부터 살펴보자.
객체 | 테이블 | |
상속 | 상속 가능 | 유사 기능: 슈퍼타입, 서브타입 관계 |
연관 관계 | 참조 | 외래키 |
객체는 연관된 것끼리 자유롭게 객체 그래프를 탐색할 수 있어야 한다.
계층형 아키텍처에서는 엔티티를 신뢰할 필요가 있다.
등을 고려해 모델링 하면 매핑 작업이 늘어난다.
여기서 JPA 가 등장하게 되는데 객체를 Java Collection에 저장하듯 DB에 저장하는 것을 지원한다.
🔻 Java Collection에 저장한다는 말의 의미
Member의 정보를 받아오려고 한다고 가정해보자.
Java Collection 같은 경우에는 아래와 같다.
List<Member> members = new ArrayList<>();
Member a = members.get(1L);
Member b = members.get(1L);
a와 b는 ==으로 비교해도 동일한 결과를 가져온다.
JDBC API를 통해 SQL 결과를 가져온다고 가정해보자.
Member a = memberDAO.getMember(1L);
Member b = memberDAO.getMember(1L);
class MemberDAO {
public Member getMember(Long memberId) {
String sql = "SELECT * FROM MEMBER WHERE MEMBER_ID = ?";
// SQL 실행
return new Member(...);
}
}
new Member를 통해 반환하므로 ==으로 비교하면 동일하지 않다.
2. JPA란?
- Java Persistence API
- 자바 진영의 ORM 표준
- Java 애플리케이션과 JDBC API 사이에서 동작
- JPA는 인터페이스의 모음으로 구현체는 Hibernate, EclipseLinke, DataNucleus가 있음.
(보통 Hibernate 사용)
🔻 ORM이란?
- Oberjct-realational mapping( 객체 관계 매핑)
- 객체는 객체대로, RDB는 RDB로 설계하고 이 둘을 매핑해주는 역할
- 대중적인 언어에는 대부분 ORM 기술이 존재
JPA 동작 과정
- MemberDAO에서 find() 호출
- SELECT SQL 생성
- JDBC API 사용해 SQL 실행 및 결과 반환
- ResultSet 매핑
- Entity Object를 MemberDAO에 반환
3. 왜 JPA를 사용해야 하는가?
SQL -> 객체 중심의 개발 가능
생산성 ↑
아래 메소드 사용 가능
- 저장: persist()
- 조회: find()
- 수정: setName()
- 삭제: remove()
유지보수 ↑
- 기존: 필드 변경 시 관련 SQL을 수정
- JPA: 필드 변경만 하면 됨 (SQL은 JPA가 처리)
패러다임의 불일치 해결
- 객체 상속 시 SQL은 JPA가 알아서 처리하므로 고려 X
- 연관 관계 저장 가능 및 객체 그래프 탐색 지원
- 동일 트랜잭션에서 조회한 엔티티는 같음을 보장 (== 사용 ok)
성능 최적화 기능
- 1차 캐시와 동일성 보장
(같은 트랜잭션 안에서는 같은 엔티티 반환.
DB Isolation Level이 Read Commit이어도 애플리케이션에서 Repaetable Rad 보장) - 트랜잭션을 지원하는 쓰기 지연; Transactional Write-Behind
(트랜잭션 커밋할때까지 insert sql을 모았다가 jdbc batch sql 기능을 사용해 한번에 전송) - 지연 로딩; Lazy Loading
: 객체가 실제 사용될 때 로딩
(↔ 즉시 로딩: JOIN SQL로 한번에 연관된 객체까지 미리 조회)
데이터베이스 방언; DB Dialect
- : 각 DB마다 조금씩 다른 SQL 문법이나 함수 (특정 DB만의 고유 기능)
- JPA는 특정 DB에 종속되지 않음
- hibernate는 약 40가지 이상의 방언 지원
4. JPA 주의 사항
- Entity Manager Factory는 하나만 생성해서 애플리케이션 전체에서 공유
- Entity Manager는 스레드 간 공유 X (사용 후 버리기)
- JPA의 모든 데이터 변경은 트랜잭션 내에서 실행
JPA를 사용하면 보통 Entity를 중심으로 개발한다.
특정 데이터를 조회하고자 할 때 모든 DB 데이터를 객체로 변환해 검색하는 것은 한계가 있다.
결국 필요한 데이터만 DB에서 불러오기 위해 검색 조건이 포함된 SQL이 필요하다.
여기서 등장한 것이 JPQL이다.
🔻 JPQL
- SQL을 추상화한 객체 지향 쿼리 언어 (=객체 지향 SQL)
- 특정 DB SQL에 의존하지 않음
JPQL: Entity 대상의 쿼리
SQL: DB 테이블 대상의 쿼리
5. JPA의 중요한 기능
JPA의 중요한 기능은 크게 두 가지로 나뉜다.
- 영속성 컨텍스트
- 객체의 RDB의 매핑
4-1. 영속성 컨텍스트란?
- Entity를 영구 저장하는 환경
- 논리적인 개념으로 눈에 보이지 않음
- Entity Manager를 통해 영속성 컨텍스트에 접근
EntityManager.persist(entity)는 정확히 말하자면 DB에 저장하는게 아니다.
엔티티 영속성 컨텍스트에 저장된다.
영속성 컨텍스트의 장점
- 1차 캐시 지원
- 동일성 보장
- 트랜잭션을 지원하는 쓰기 지연
- 변경 감지; Dirty Checking
: 조회 후 객체를 변경하면 변경이 감지되면 자동으로 update됨 - 지연 로딩; Lazy Loading
Flush
- 영속성 컨텍스트의 변경 내용을 DB에 반영
(!= 영속성 컨텍스트 비우기) - 변경 감지, 수정된 Entity 쓰기 지연 SQL 저장소에 등록, 쓰기 지연 SQL 저장소의 쿼리를 DB에 전송 시 발생
- Entity Manager의 flush()를 통해 직접 호출 가능
- 트랜잭션 커밋, JPQL 쿼리 실행 시 자동 호출
엔티티의 생명주기
- 비영속 (new; transient): 영속성 컨텍스트와 관계 없는 새로운 상태
- 영속 (managed): 영속성 컨텍스트에 관리되는 상태
- 준영속 (detached): 영속성 텍스트에 저장되었다 분리된 상태
- 삭제 (removed): 삭제된 상태
준영속 상태
- 영속 상태의 entity가 영속성 컨텍스트에서 분리됨
(= 영속성 컨텍스트 가 제공하는 기능 사용 불가) - .detach(entity): 특정 엔티티만 준영속 상태로 전환
- .clear(): 영속성 컨텍스트 완전히 초기화
- .close(): 영속성 컨텍스트 종료
4-2. 객체의 RDB 매핑
이에 대해서는 다양한 기능을 지원하므로 글을 별도로 작성한다.
https://yeonyeon.tistory.com/179
본 게시글은 김영한 님의 '자바 ORM 표준 JPA 프로그래밍 - 기본편' 강의를 구매 후 정리하기 위한 포스팅입니다.
내용을 임의로 추가, 수정, 삭제한 부분이 많으며 정확한 이해를 위해서 강의를 구매하시는 것을 추천 드립니다.
'Develop > JPA' 카테고리의 다른 글
[JPA] Table 'DB.hibernate_sequence' doesn't exist 에러 (0) | 2022.01.14 |
---|---|
[JPA] 프록시와 영속성 전이 (0) | 2022.01.13 |
[JPA] Entity 매핑 (0) | 2022.01.10 |
[MVC] 어댑터 추가 (0) | 2021.05.19 |
[JPA] 더티 체킹 (0) | 2021.01.18 |