2 분 소요


JPA 왜 사용하는가?

과거에 객체를 DB에 저장하려면 복잡한 JDBC API, SQL을 등록해야했다.
JDBCTemplate에서 개발코드는 많이 줄었지만 sql은 다 작성해야했다.
JPA는 이 sql조차 작성할 필요가 없다.

그 밖에 객체를 자바 컬렉션에 저장하듯이 DB에 저장하기 위해서 사용한다.

객체/관계형 데이터베이스 차이

  1. 상속
  2. 연관관계
  3. 데이터 타입
  4. 데이터 식별 방법

상속

1

Album 저장

  1. 객체 분해
  2. INSERT INTO ITEM …
  3. INSERT INTO ALBUM …

Album 조회

  1. 각각의 테이블에 따른 조인 SQL 작성
  2. 각각의 객체 생성

(그 밖에 복잡한 과정 생략…)


자바 컬렉션

저장
list.add(album);

조회
Album album = list.get(albumId);

연관관계

2

  • 객체는 참조를 사용: member.getTeam()
  • 테이블은 외래 키를 사용: JOIN ON M.TEAM_ID = T.TEAM_ID

테이블에 맞추어 모델링

class Member {
    String id;
    Long teamId;
    String username;
}
class Team {
    Long id;
    String name;
}

테이블에 맞춘 객체 저장

INSERT INTO MEMBER(MEMBER_ID, TEAM_ID, USERNAME) VALUES ...


JPA

  • Java Persistence API
  • 자바 진영의 ORM 기술 표준
  • EJB - 엔티티 빈(자바 표준) -> 하이버네이트(오픈 소스) -> JPA(자바 표준)
  • JPA는 인터페이스의 모음
  • JPA 2.1 표준 명세를 구현한 3가지 구현체
    • 하이버네이트, EclipseLink, DataNucleus

ORM

  • Object-relational mapping(객체 관계 매핑)
  • 객체는 객체대로 설계
  • 관계형 데이터베이스는 관계형 데이터베이스대로 설계
  • ORM 프레임워크가 중간에서 매핑
  • 대중적인 언어에는 대부분 ORM 기술이 존재

JPA 동작

3

JPA는 애플리케이션과 JDBC 사이에서 동작한다.

동작 예시(저장)

4

JPA 사용 이유?

  • SQL 중심적인 개발에서 객체 중심으로 개발
  • 생산성
  • 유지 보수
  • 패러다임의 불일치 해결
  • 성능
  • 데이터 접근 추상화와 벤더 독립성
  • 표준

생산성

JPA와 CRUD

  • 저장: jpa.persist(member)
  • 조회: Member member = jpa.find(memberId)
  • 수정: member.setName(“변경할 이름”)
  • 삭제: jpa.remove(member)

유지 보수

  • 기존: 필드 변경시 모든 SQL 수정
  • JPA: 필드만 추가하면 SQL은 JPA가 자동으로 처리
    public class Member {
      private String memberId;
      private String name;
      private String tel; // 추가 코드
    }
    

    SQL은 JPA가 자동으로 처리해 주기 때문에 유지 보수가 간단하다.

패러다임 불일치 해결

  1. JPA와 상속
  2. JPA와 연관관계
  3. JPA와 객체 그래프 탐색
  4. JPA와 비교하기

JPA와 상속

1

저장
  • 개발자가 할 일
    • 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();
    

JPA와 비교

String memberId = "100";
Member member1 = jpa.find(Member.class, memberId);
Member member2 = jpa.find(Member.class, memberId);

// 결론
member1 == member2; // 같다

동일한 트랜잭션에서 조회한 엔티티는 같음을 보장

JPA의 성능 최적화

  1. 1차 캐시와 동일성(identity) 보장
  2. 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)
  3. 지연 로딩(Lazy Loading)

1차 캐시와 동일성 보장

  1. 같은 트랜잭션 안에서는 같은 엔티티를 반환 - 약간의 조회 성능 향상(거의 효과X)
  2. DB Isolation Level이 Read Commit이어도 애플리케이션에서 Repeatable Read 보장
String memberId = "100";
Member member1 = jpa.find(Member.class, memberId);
Member member2 = jpa.find(Member.class, memberId);

println(m1 == m2); // true

결론 : SQL 한번만 실행

쓰기 지연

  1. 트랜잭션을 커밋할 때 까지 INSERT SQL을 모음
  2. JDBC BATCH SQL 기능을 사용해서 한번에 SQL 전송
transaction.begin();    // 트랜잭션 시작

em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
// 여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.

// 커밋하는 순간 데이터베이스에 INSERT SQL을 모아서 보낸다.
transaction.commit();   // 트랜잭션 커밋

지연 로딩과 즉시 로딩

  • 지연 로딩: 객체가 실제 사용될 때 로딩
  • 즉시 로딩: JOIN SQL로 한번에 연관된 객체까지 미리 조회
  • 로딩 설정은 코드로 변경할 수 있다.

5

실무에서는 우선 지연 로딩으로 설계를 해 놓은 뒤에 최적화시 필요한 부분을 즉시 로딩으로 설정


<출처 : 인프런 - 자바 ORM 표준 JPA 프로그래밍 - 기본편 (김영한)>

댓글남기기