JPA) 소개
Date: Updated:카테고리: java
JPA?
- Java Persistence API의 줄임말
-
자바 진영의 ORM 기술 표준
- 역사
- EJB
- 과거 자바 ORM 표준이었다.
- 너무 많은 인터페이스들의 구현을 요구함
- 안좋은 퍼포먼스
- 기능이 잘 동작하지 않음
- Hibernate의 등장
- EJB를 사용하던 어느 개발자(Gavin King)가 기존 EJB를 대체할 목적으로 만듬.
- Open source ORM Framework
- JPA
- 자바 진영에서 Hibernate를 개발한 Gavin King을 데려와 Hibernate 기반으로 개발
- 인터페이스의 모음이다.
- JPA 2.1 표준 명세를 구현한 대표적인 구현체로는 Hibernate, EclipseLink, DataNucleus가 있다.
- 버전
- JPA 1.0(JSR 220) 2006년 : 초기 버전. 복합 키와 연관관계 기능이 부족
- JPA 2.0(JSR 317) 2009년 : 대부분의 ORM 기능을 포함, JPA Criteria 추가
- JPA 2.1(JSR 338) 2013년 : 스토어드 프로시저 접근, 컨버터(Converter), 엔티티 그래프 기능이 추가
- EJB
ORM?
- Object-relational mapping(객체 관계 매핑)
- 사용자는 객체는 객체대로 설계하고, 관계형 데이터베이스는 관계형 데이터베이스대로 설계하자.
- 그러면 ORM 프레임워크가 중간에서 매핑을 해준다.
- 대중적인 언어에는 대부분 ORM 기술이 존재한다. (TypeORM, Python 등)
JPA를 사용해야하는 이유
SQL 중심적인 개발에서 객체 중심으로 개발
JPA 사용해야하는 이유 (SQL 의존적 개발의 문제) 참고
생산성
- 마치 자바 컬렉션 객체에서 데이터를 활용하듯 쉽게 사용할 수 있다.
- 저장 :
jpa.persist(member)
- 조회 :
Member member = jpa.find(member)
- 수정 :
member.setName("name")
- 특히 수정이 굉장히 편리하다.
- 객체 속성을 바꾸기만 하면 JPA가 알아서 DB에 UPDATE SQL을 던진다.
- 삭제 :
jpa.remove(member)
- 저장 :
유지보수
- 기존 SQL 중심적인 개발에서는 객체 속성이 바뀔때마다 SQL도 수정했어야 했음.
- JPA가 Entity를 분석하여 SQL을 생성하기 때문에 객체만 수정하면 됨
패러다임의 불일치 해결
- 상속
- JPA가 객체 간의 구조를 파악하여 알맞은 SQL을 생성함.
- 때문에 개발자는 SQL을 신경쓰지 않고 객체 기준으로 개발하면 됨.
- 저장
- 개발자가 할일
jpa.persist(album);
- JPA가 처리
INSERT INTO ITEM ...
INSERT INTO ALBUM ...
- 개발자가 할일
- 조회
- 개발자가 할일
Album album = jpa.find(Album.class, albumId);
- JPA가 처리
SELECT I.*, A.* FROM ITEM I JOIN ALBUM A ON I.ITEM_ID = A.ITEM_ID
- 개발자가 할일
- 연관관계 및 객체 그래프 탐색
- 객체의 참조만으로 마치 자바 컬렉션 객체를 다루듯 연관관계 저장 및 객체 그래프 탐색이 가능하다.
- 연관관계 저장
member.setTeam(team);
jpa.persist(member);
- 객체 그래프 탐색
Member member = jpa.find(Member.class, memberId);
Team team = member.getTeam();
- 연관관계 저장
- 객체의 참조만으로 마치 자바 컬렉션 객체를 다루듯 연관관계 저장 및 객체 그래프 탐색이 가능하다.
- 신뢰할 수 있는 엔티티
class MemberService { ... public void process() { Member member = memberDAO.find(memberId); member.getTeam(); //자유로운 객체 그래프 탐색 member.getOrder().getDelivery(); } }
- JPA의 지연 로딩 전략(Lazy Loading)을 통해 자유롭게 객체 그래프 탐색이 가능하다!
비교하기
String memberId = "100";
Member member1 = jpa.find(Member.class, memberId);
Member member2 = jpa.find(Member.class, memberId);
member1 == member2; //같다.
- JPA는 동일한 트랜잭션에서 조회한 엔티티는 같음을 보장한다.
성능 최적화
- 1차 캐시와 동일성(identity) 보장
- 같은 트랜잭션 안에서는 같은 엔티티를 반환 (캐시를 활용한다.)
String memberId = "100"; Member member1 = jpa.find(Member.class, memberId); //SQL Member member2 = jpa.find(Member.class, memberId); //캐시에 저장한 것을 호출 member1 == member2; //같다.
- 결과적으로 동일한 Entity에 대해서 SQL을 2번 호출하지 않고 1번만 호출한다!
- DB Isolation Level이 Read Commit이어도 애플리케이션에서 Repeatable Read를 보장한다.
- 같은 트랜잭션 안에서는 같은 엔티티를 반환 (캐시를 활용한다.)
- 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)
- INSERT
transaction.begin(); em.persist(memberA); em.persist(memberB); em.persist(memberC); //여기까지 INSERT SQL을 DB에 보내지 않는다. // 커밋하는 순간 DB에 INSERT SQL을 한번에 보낸다. transaction.commit();
- 트랜잭션을 커밋할 때까지 INSERT SQL을 모은다.
- JDBC BATCH SQL 기능을 사용해서 한번에 SQL을 전송한다.
- 네트워크 3번 연결될 것을 1번에 모두 수행하여 성능을 최적화한다. (지연 로딩 전략)
- UPDATE
transaction.begin(); changeMember(memberA); deleteMember(memberB); 비즈니스_로직(); // 비즈니스 로직 수행동안 DB ROW 락이 걸리지 않는다. // 커밋하는 순간 DB에 UPDATE, DELETE SQL을 보낸다. transaction.commit();
- UPDATE, DELETE로 인한 로우(ROW)락 시간 최소화
- 트랜잭션 커밋 시 UPDATE, DELETE SQL 실행하고 바로 커밋
- INSERT
- 지연 로딩(Lazy Loading)
- 지연 로딩
- 객체가 실제 사용될 때 로딩
member.getTeam()
으로 객체를 선언 했더라도 실제로 사용하지 않으면 SQL을 던지지 않음.team.getName()
을 통해 Team 객체가 사용되자 그때 SQL을 던진다.- 단, 객체의 실제 사용 시점에 쿼리를 던지므로 결과적으로 봤을 때 쿼리를 많이 던지는 형태가 될 수 있음.
- 현재 예제에선 네트워크를 2번 거침
- 즉시 로딩
- JOIN SQL로 한번에 연관된 객체까지 미리 조회
- 옵션을 통해 특정 객체를 조회 할 때 한번에 연관된 객체를 전부 조회한다.
- 위의 지연 로딩으로 조회했을 때보다 경제적임
- 현재 예제에서 네트워크를 1번만 거침
- 지연 로딩
JPA의 동작 과정
- Java application과 JDBC 사이에서 동작한다.
- 개발자가 직접 JDBC를 사용하지 않고 JPA를 사용하여 명령을 전달하면 내부에서 JDBC를 통해 DB와 통신한다.
저장
- Member 객체를 저장하고 싶을 때
- 개발자가 MemberDAO를 통해 JPA로 Member 객체를 넘긴다.
- JPA가 Member 객체(Entity)를 분석한다.
- JPA가 INSERT SQL을 생성한다.
- JPA가 JDBC API를 사용하여 INSERT SQL을 DB에 던진다.
조회
- Member 객체를 조회하고 싶을 때
- 개발자가 MemberDAO를 통해 JPA로 Member 객체(Entity)의 PK에 해당하는 값을 넘긴다.
- JPA가 SELECT SQL을 생성한다.
- JPA가 JDBC API를 사용하여 SELECT SQL을 DB에 던진다.
- JPA가 JDBC API를 사용하여 DB로부터 결과 값(ResultSet)을 받은 뒤 해당 객체에 매핑해준다.
마무리
- ORM은 객체와 RDB 두 기둥위에 있는 기술이다.
- JPA만 잘한다고 해서 잘하는 것이 아니고, RDB만 잘한다고 해서 잘하는 것이 아니다.
- 한쪽만 치우치면 제대로 활용할 수 없으며 둘다 제대로 활용해야 한다!
- JPA / RDB 둘다 공부 열심히…
📣 Reference
본 포스팅은 김영한님의 강의를 듣고 스스로 정리 및 추가한 내용입니다.
댓글남기기