JPA) 소개

Date:    Updated:

카테고리:

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가 있다.
      • image
      • 버전
        • JPA 1.0(JSR 220) 2006년 : 초기 버전. 복합 키와 연관관계 기능이 부족
        • JPA 2.0(JSR 317) 2009년 : 대부분의 ORM 기능을 포함, JPA Criteria 추가
        • JPA 2.1(JSR 338) 2013년 : 스토어드 프로시저 접근, 컨버터(Converter), 엔티티 그래프 기능이 추가

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을 생성하기 때문에 객체만 수정하면 됨

패러다임의 불일치 해결

  • 상속
    • image
    • 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 실행하고 바로 커밋
  • 지연 로딩(Lazy Loading)
    • image
    • 지연 로딩
      • 객체가 실제 사용될 때 로딩
      • member.getTeam() 으로 객체를 선언 했더라도 실제로 사용하지 않으면 SQL을 던지지 않음.
      • team.getName()을 통해 Team 객체가 사용되자 그때 SQL을 던진다.
      • 단, 객체의 실제 사용 시점에 쿼리를 던지므로 결과적으로 봤을 때 쿼리를 많이 던지는 형태가 될 수 있음.
        • 현재 예제에선 네트워크를 2번 거침
    • 즉시 로딩
      • JOIN SQL로 한번에 연관된 객체까지 미리 조회
      • 옵션을 통해 특정 객체를 조회 할 때 한번에 연관된 객체를 전부 조회한다.
      • 위의 지연 로딩으로 조회했을 때보다 경제적임
        • 현재 예제에서 네트워크를 1번만 거침

JPA의 동작 과정

image

  • Java application과 JDBC 사이에서 동작한다.
  • 개발자가 직접 JDBC를 사용하지 않고 JPA를 사용하여 명령을 전달하면 내부에서 JDBC를 통해 DB와 통신한다.

저장

image

  • Member 객체를 저장하고 싶을 때
    • 개발자가 MemberDAO를 통해 JPA로 Member 객체를 넘긴다.
    • JPA가 Member 객체(Entity)를 분석한다.
    • JPA가 INSERT SQL을 생성한다.
    • JPA가 JDBC API를 사용하여 INSERT SQL을 DB에 던진다.

조회

image

  • 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

본 포스팅은 김영한님의 강의를 듣고 스스로 정리 및 추가한 내용입니다.

자바 ORM 표준 JPA 프로그래밍 - 기본편

댓글남기기