JPA

JPA 소개

엔꾸꾸 2020. 6. 6. 23:01

서론

 

현대에 와서 대부분의 자바 애플리케이션들은 관계형 데이터베이스 를 데이터 저장소로 사용한다.

데이터베이스를 활용해서 데이터를 관리하려면 결국 SQL 을 사용해야한다.

 

SQL 을 직접 다룰때 발생하는 문제

 

반복, 그리고 SQL 의존적인 개발

 

일반적으로 회원 관련 기능을 만든다고 가정했을때의 간단한 예제를 살펴보자.

 

// 엔티티 클래스
class Member {
  private String memberId;
  private String name;
}

// DAO 클래스
class MemberDAO {
 private Member find(String memberId) {...}
 private void save(Member member) {...}
}
INSERT INTO MEMBER VALUES (...)
UPDATE MEMBER SET ... WHERE ...

 

  1. 회원 <기능명> SQL 을 작성한다.

  2. JDBC API를 사용해서 SQL을 실행한다.

  3. 결과를 Mapping 해서 반환한다.

 

문제점

 

만약 회원 테이블의 컬럼이 추가/수정 될 경우 모든 SQL에 수정 작업이 필요하다.
개발자도 사람이기 때문에 휴먼에러 (오타 등) 에 취약하다.
컴파일 시점에 에러를 찾을 수 없다.

 

가장 큰 문제점은 Layered Architechture 의 의미가 사라진다.

해당 계층을 신뢰하고 사용할 수 있어야 하는데, 해당 계층을 신뢰할 수 없게 된다.

Member -> Team 의 관계에서 MemberDAO.find() 를 했을때 Team 에 대한 정보를 함께 가져오는지는, 직접 SQL 까지 까봐야 알 수 있다.

 

 

 

JPA

 

JPA 란 무엇인가 ?

JPA는 Java Persistence API 의 약자로, 자바 진영의 ORM 표준 기술이다.

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

 

 

 

ORM 이란 ?

  • Object Relation Mapping 의 약자

  • 객체와 관계형 데이터베이스를 매핑한다.

  • 객체와 테이블을 매핑하여 패러다임의 불일치 문제를 개발자 대신 해결해준다.

 

JPA 소개

 

과거에는 자바 빈즈 (EJB) 라는 기술 표준을 만들었는데, 그 안에는 엔티티 빈이라는 ORM 기술도 포함되어 있었다.

하지만 너무 복잡하고 기술 성숙도도 떨어졌으며 J2EE 서버에서만 동작했고, 이 때 하이버네이트라는 오픈소스가 등장하게 된다.

자바 진영에서 하이버네이트 개발자를 앉혀놓고 만든것이 JPA, 새로운 자바 ORM 기술 표준이다.

 

 

 

JPA를 사용해야하는 이유 ?

 

  1. 생산성
    • JPA 를 사용하면 자바 컬렉션에 객체를 관리하듯이 저장, 조회 할 수 있다.

    • 반복적인 일은 JPA가 대신 처리해준다.

  2. 유지 보수
    • 엔티티에 필드 하나만 추가해도 관련된 등록, 수정, 조회 SQL 과 결과 매핑을 위한 처리를 JPA가 대신 처리해준다.

    • 엔티티가 변경되어도, 수정해야 할 코드가 줄어든다.

  3. 패러다임의 불일치 해결
    • 상속, 연관관계, 객체 그래프탐색, 비교하기 와 같은 패러다임 불일치 문제를 해결 해 준다.

  4. 성능
    • 관계형 데이터베이스 사이에서 다양한 성능 최적화 기회를 제공한다.

  5. 데이터 접근 추상화와 벤더 독립성
    • 관계형 데이터베이스는 벤더마다 사용법이 다른 경우가 많은데, JPA는 애플리케이션과 데이터베이스 사이에 추상회된 데이터 접근 계층을 제공하여, 특정 벤더에 종속되지 않도록 한다.

 

패러다임의 불일치 해결

 

객체지향 프로그래밍은 추상화, 캡슐화 정보은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 다양한 장치들을 제공한다.

현대의 복잡한 애플리케이션은 대부분 객체지향 언어로 개발 한다.

문제는 비즈니스 모델을 객체로 모델링한 도메인 모델을 저장할 때 발생한다.

결국 관계형 데이터베이스에 저장을 해야하는데 여기서 발생하는 패러다임의 불일치를 해결하기 위해, 너무 많은 시간과 코드를 소비한다.

 

 

 

상속

 

객체는 상속이라는 기능을 가지고 있지만, 테이블은 상속이라는 기능이 없다.

그나마 유사한 모델이 슈퍼타입/서브타입 관계형 모델을 사용하는 것이다.

JPA 는 상속과 관련된 패러다임의 불일치 문제를 개발자 대신 해결 해 준다.

마치 자바 컬렉션이 객체를 저장하듯이 JPA에 객체를 저장하면 된다.

 

class Item {
  Long id;
  String name;
  int price;
}

class Album extends Item {
  String artist;
}
  
jpa.persist(album); // 저장

Album album = jpa.find(Album.class, "id0001"); // 조회
INSERT INTO ITEM ...
INSERT INTO ALBUM ... // 저장

SELECT I.*, A.*
FROM ITEM I
JOIN ALBUM A ON I.ITEM_ID = A.ITEM_ID // 조회

 

 

 

연관관계

 

객체는 참조를 통해 연관객체에 접근하지만, 테이블은 외래키를 이용한 조인을 사용해 연관 테이블을 조회한다.

가장 큰 차이점은 객체는 근본적으로 방향이 존재하지만, 테이블은 방향이 존재하지 않는다.

 

 

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

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

class Team {
  Long id;
  String name;
}
테이블의 컬럼을 객체의 타입에 그대로 맞추어 매핑한 설계 방식이다.
하지만 객체지향의 장점을 살리려면 객체의 참조를 활용해야 한다.

 

객체지향 모델링

class Member {
  String id;
  String username;
  Team team;
}

class Team {
  Long id;
  String name;
}

Member member = jpa.find(Member.class, 1L);
member.getTeam(); // 참조를 통한 팀의 조회가 가능해진다.
JPA는 연관관계와 관련된 패러다임의 불일치를 해결해준다.
Member -> Team 의 관계를 설정하고 Member의 객체를 저장하면 참조를 외래키로 변환하여 SQL로 전달한다.

 

객체 그래프 탐색

 

SQL을 직접 다루면 처음 실행하는 SQL에 따라 객체 그래프를 어디까지 탐색할 수 있는지 정해진다.

class MemberService {
  public void process() {
    Member member = memberDAO.find(1L);
    member.getTeam(); // ??
    member.getOrder().getDelivery(); // ??
  }
}
JPA를 사용하면 객체 그래프를 마음껏 탐색할 수 있다.
JPA는 실제 객체를 사용하는 시점에 지연로딩 을 사용해 데이터베이스에서 조회를 한다.

 

 

비교

 

데이터베이스는 기본 키의 값으로 각 로우를 구분한다.

객체는 동일성 비교와 동등성 비교라는 두가지 방법이 있다.

  • 동일성 비교는 ==, 객체의 인스턴스 주소값을 비교한다.

  • 동등성 비교는 equals() 메소드를 사용해서 객체의 내부 값을 비교한다.

String memberId = "USER_001";

Member member1 = list.get(memberId);
Member member2 = list.get(memberId);

member1 == member2; // true

 

JPA는 같은 트랜잭션 일 때 같은 객체가 조회되는 것을 보장한다.