Link Search Menu Expand Document

JPA 소개

SQL 중심적인 개발의 문제점

  • 관계형 DB (Oracle, MySQL)에서는 SQL만 사용할 수 있으므로 SQL 의존적인 개발을 할 수 밖에 없다.
  • 관계형 DB의 목적과 객체지향 프로그래밍의 목적이 일치하지 않는다. 그러나, 객체를 저장할 수 있는 가장 현실적인 방안은 관계형 DB이다.

객체와 관계형 데이터베이스의 차이

  1. 상속

JPA 소개 - 상속

DB에서는…

Album 객체를 저장할 경우 : 객체를 분해하여 artist는 album에 저장, name, price, dtype은 item에 저장 Album 객체를 조회할 경우 : 각 테이블을 조회하는 Join SQL 작성, 각각의 객체 생성… 복잡 그래서 DB에 저장할 객체에는 상속 관계를 쓰지 않는다.

자바에서는…

Album 객체를 저장할 경우 : list.add(album); Album 객체를 조회할 경우 :Album album = list.get(albumId); :arrow_right: Item item = list.get(albumId); 부모 타입으로 조회 후 다형성을 활용할 수도 있다.

  1. 연관관계

JPA 소개 - 연관관계

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

객체를 테이블에 맞추어 모델링

class Member {
	String id;		// MEMBER_ID
	Long teamId;	// TEAM_ID FK
    String username;// USERNAME
}

class Team {
	Long id;		// TEAM_ID PK
	String name;	// NAME
}

객체다운 모델링

class Member {
	String id;		// MEMBER_ID
	Team team;		// 참조로 연관관계를 맺는다
    String username;// USERNAME
    
    Team getTeam() {
        return team;
    }
}

class Team {
	Long id;		// TEAM_ID PK
	String name;	// NAME
}

객체 모델링 조회

SELECT M.*, T.*
  FROM MEMBER M
  JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
public Member find(String memberId) {
    // SQL 실행
    Member member = new Member();
    // 데이터베이스에서 조회한 회원 관련 정보 입력
    Team team = new Team();
    // 데이터베이스에서 조회한 팀 관련 정보 입력
    
    // 회원과 팀 관계 설정
    member.setTeam(team);
    return member;
}

이는 굉장히 번거로운 작업이다.

객체 그래프 탐색

객체는 자유롭게 객체 그래프를 탐색할 수 있어야 한다. 하지만 실행하는 SQL에 따라 탐색 범위가 결정되기 때문에 SQL 중심적인 개발에서는 그것이 불가능하다.

엔티티 신뢰 문제

class MemberService {
    public void process() {
        Member member = memberDAO.find(memberId);
        member.getTeam(); // 사용 가능한가?
        member.getOrder().getDelivery(); // 사용 가능한가?
    }
}

SQL에서 탐색된 객체 이외에는 사용할 수 없으므로 엔티티를 신뢰할 수 없다. 계층 아키텍쳐에서는 이전 계층에서 넘어온 내용을 신뢰할 수 있어야 하는데 SQL 중심적인 개발에서는 그것이 불가능하므로 객체가 SQL에 의존한다.그렇다고 모든 객체를 미리 로딩할 수 없으므로 상황에 따라 동일한 회원 조회 메서드를 여러 벌 생성해야 한다.

  1. 비교하기
String memberId = "100";
Member member1 = memberDAO.getMember(memberId);
Member member2 = memberDAO.getMember(memberId);

member1 == member2; // 다르다.
String memberId = "100";
Member member1 = list.get(memberId);
Member member2 = list.get(memberId);

member1 == member2; // 같다.

SQL 중심적인 개발에서는 getMember()을 호출할 때 New Member()로 객체를 생성하기 때문에 member1member2가 다르다. 그러나 자바 컬렉션에서 조회할 경우 member1member2의 참조 값이 같기 때문에 두 객체는 같다.

이렇게 객체를 객체답게 모델링할수록 매핑 작업만 늘어난다.

JPA 소개

JPA?

  • Java Persistence API
  • 자바 진영의 ORM 기술 표준

ORM?

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

JPA 동작

저장

JPA 소개 - JPA 동작 - 저장

조회

JPA 소개 - JPA 동작 - 조회

JPA는 표준 명세

  • JPA는 인터페이스의 모음
  • JPA 2.1 표준 명세를 구현한 3가지 구현체
  • 하이버네이트, EclipseLink, DataNucleus

JPA 소개 - JPA는 표준 명세

JPA를 왜 사용해야 하는가?

  • SQL 중심적인 개발에서 객체 중심으로 개발

  • 생산성

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

    • 기존에는 필드 변경시 모든 SQL 문을 수정해야 했지만, JPA에서는 필드만 추가하면 SQL은 JPA가 처리한다.
  • 패러다임의 불일치 해결

    1. JPA와 상속 : 특정 객체를 저장할 경우 상속 관계를 JPA가 분석하여 필요한 쿼리를 JPA가 생성한다.

    2. JPA와 연관관계, JPA와 객체 그래프 탐색 : 지연 로딩을 사용하여 신뢰할 수 있는 엔티티, 계층을 제공한다.

    3. JPA와 비교하기 : 동일한 트랜잭션에서 조회한 엔티티는 같음을 보장한다.

  • 성능 최적화 기능

    1. 1차 캐시와 동일성(identity) 보장

      1. 같은 트랜잭션 안에서는 같은 엔티티를 반환 - 약간의 조회 성능 향상
      2. DB Isolation Level이 Read Commit이어도 애플리케이션에서 Repeatable Read 보장
    2. 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)

      1. 트랜잭션을 커밋할 때까지 INSERT SQL을 모음
      2. JDBC BATCH SQL 기능을 사용해서 한번에 SQL 전송
      3. UPDATE, DELETE로 인한 로우(ROW)락 시간 최소화
      4. 트랜잭션 커밋 시 UPDATE, DELETE SQL 실행하고, 바로 커밋
    3. 지연 로딩(Lazy Loading)

      지연 로딩: 객체가 실제 사용될 때 로딩 즉시 로딩: JOIN SQL로 한번에 연관된 객체까지 미리 조회

    JPA 소개 - 지연 로딩과 즉시 로딩

  • 데이터 접근 추상화와 벤더 독립성

  • 표준

ORM은 객체와 RDB 두 기둥 위에 있는 기술이다.