1. JPA의 개념

xellos·2022년 6월 14일
0

JPA

목록 보기
2/7

SQL 을 직접 다루는 경우

  1. 회원 조회용 SQL 을 작성한다.
SELECT id, name FROM member where id = ?
  1. JDBC API 를 사용해서 SQL을 실행한다.
ResultSet rs = stmt.executeQuery(sql);
  1. 조회 결과를 Member 객체로 매핑한다.
String memberId = rs.getString("id");
String name = rs.getString("name");

Member member = new Member();
member.setMemberId(memberId);
member.setName(name);

여기서는 데이터를 하나 조회하고 결과를 매핑하였다. 그러나 개발이 계속되고 그에 따라 추가적으로 기능이 필요할 때마다 SQL을 작성하고 매번 그 결과를 매핑해야 할 것이다.

만약 DB가 아니라 자바 컬렉션을 사용하면 다음과 같을 것이다.

  • 이러한 차이가 발생하는 근본적인 이유는 DB는 객체 구조와 다른 데이터 중심의 구조를 가지기 때문에 객체를 직접 저장하거나 조회할 수 없기 때문이다.
  • 그에 따라 개발자는 앱과 DB 중간에서 JDBC API 를 사용해서 변환작업을 직접 해야한다.
Member member = new Member();
Map<String, String> memberStorage = new HashMap<>();
memberStore.put(member.getId(), member); 	//저장
memberStore.get(member.getId());			//조회

1) 데이터가 변경된다면?

위와 같은 상황에서 데이터가 변경된다면 어떻게 될까? 가령 Member에 age 멤버변수가 추가된다면? 그렇게 되면 SQL 에서 age를 가져오도록 수정하고 추가로 age역시 객체에 추가로 매핑을 해주어야 한다. 일반적으로는 DAO를 사용하므로 이 역시 수정되어야 한다.

2) 연관된 객체 조회

class Member {
	private String memberId;
	private String name;
	private String age;
	private Team team;
}

class Team {
	private String teamName;
}

위와 같은 Member 클래스와 Team 클래스가 있다고 할 때 이 둘의 조회는 어떻게 될까?

아마 다음과 같은 SQL을 작성하고 그 결과를 각기 따로 매핑한 후 연관관계를 설정해야 할 것이다.

  • 이때 위에서 설명한 것처럼 또 SQL을 작성하고 수많은 매핑과 연관관계를 설정해야 한다.
  • 또 다른 문제는 Member 객체가 연관된 Team 객체를 사용할 수 있는지 여부가 SQL에 달려 있다는 것이다.
  • 즉, 앱의 로직 단계에서 겉보기에는 객체의 연관관계를 사용하는것 처럼 보이지만 실제로 이를 알기 위해서는 작성한 SQL문을 봐야한다는 것이다.
SELECT member.* , team.*
FROM member
	JOIN team ON team.id = member.team_id

3) 정리

  • 진정한 의미의 계층 분할이 어렵다.
  • 엔티티를 신뢰할 수 없다.
  • SQL 의존적인 개발을 피하기 어렵다.

패러다임의 불일치

애플리케이션은 자바로는 객체지향 언어로 개발을 하고 데이터는 관계형 DB 에 저장해야 한다면, 패러다임의 불일치 문제를 중간에서 개발자가 해결해야 한다. 대표적인 불일치 문제가 바로 객체는 참조를 통하여 관련 있는 다른 데이터(객체)에 접근을 하고 DB 는 외부키(FK) 로 다른 데이터(테이블)에 접근을 한다는 것이다.

1) 상속

위는 클래스에서의 상속이다. 클래스에서는 자식클래스가 부모 클래스의 참조(super)를 가지고 있으며, 이로 인하여 부모 객체의 멤버 변수를 자식 클래스에서 사용할 수 있다.


반면 위의 모델링은 DB의 모델링으로, 상속을 DB에서 비슷하게 구현하기 위해서는 슈퍼 타입 - 서브 타입 관계를 사용하여 상속과 유사하게 테이블을 설계하였다. 이때, 상속과 비슷하게 서브 타입 테이블이 슈퍼 타입 테이블의 키를 가지고 있어야 하며, 부모 테이블에서는 DTYPE 컬럼을 사용해서 어쩐 자식 테이블과 관계가 있는지 정의했다.

위에서 발생하는 문제는 아래와 같이 객체는 한 번만 저장하면 되지만 테이블은 2 번의 INSERT 문이 필요하다.

  • 객체
Album album = new Album();
  • DB
INSERT INTO item VALUES(...);
INSERT INTO album VALUES(...);

2) 연관관계

위에서 본 것 처럼 연관관계를 설정하기 위해서 객체는 Team의 참조를, 테이블은 다른 외부키(FK)를 가진다. 이때 둘 사이에 큰 차이가 존재하는데 객체는 서로 알게하려면 서로가 서로의 참조를 가지고 있어야 하지만 테이블을 한 쪽이 외부 키를 가지고 있으면 자동으로 서로 조회가 가능하다는 것이다.

3) 객체 그래프 탐색

객체 그래프 탐색은 위에서 언급한 것 처럼 그 범위가 SQL에 의해 처음부터 정해져있다. 그에 따라 객체 관계가 늘어나거나 변경이 생김에 따라서 수정의 범위가 기하급수적으로 늘어나게 된다.
-> 이는 엔티티가 SQL에 논리적으로 종속되어서 발생하는 문제이다.

따라서 만약 SQL 범위를 초과하는 객체 그래프 탐색시 NPE가 발생한다.

4) 비교

DB는 기본 키의 값으로 각 row 를 구분한다. 반면 객체는 동일성 비교와 동등성 비교라는 두 가지 비교 방법이 있다.
동일성 비교는 == 비교다. 객체 인스턴스의 주소 값을 비교한다.
동등성 비교는 equals() 메서드를 오버라이딩하여 객체 내부의 값을 비교한다.

따라서 테이블의 로우를 구분하는 방법과 객체를 구분하는 방법에는 차이가 존재한다.

테이블에서 조회

String memberId = "100";
Member m1 = memberDAO.getMember(memberId);
Member m2 = memberDAO.getMember(memberId);

m1 == m2 // false

객체

Member m1 = list.get(0);
Member m2 = list.get(0);

m1 == m2 //true

JPA 란?

JPA(Java Persistence API)는 자바 진영의 ORM 기술 표준이다. 아래와 같이 JDBC 사이에서 동작한다.

1) ORM 이란?

이름 그대로 객체와 관계형 DB를 매핑한다는 뜻이다. ORM 프레임워크는 객체와 테이블을 매핑해서 패러다임의 불일치 문제를 개발자 대신 해결해준다. 예를 들어 ORM 프레임 워크를 사용하면 객체를 DB에 저장할 때 INSERT 문을 직접 작성하는 것이 아니라 객체를 마치 자바 컬렉션에 저장하듯이 ORM 프레임워크에 저장하면 된다.

  • INSERT
  • SELECT

ORM 프레임워크는 단순히 SQL을 개발자 대신 생성해서 DB에 전달해주는 것 뿐만 아니라 앞서 설명한 다양한 패러다임의 문제도 해결해준다.

2) 하이버네이트

과거 JPA 이전 자바 진영에 EJB라는 표준 기술이 있었는데 이 안에 ORM 기술도 있었다. 하지만 단점이 너무 많았고, 이때 하이버네이트라는 오픈소스 ORM 프레임워크가 등장했는데 이 기술은 실용적이고 기술 성숙도도 높았다.
결국 EJB 3.0 에서 하이버네이트를 기반으로 새로운 자바 ORM 기술 표준이 만들어졌고 이것이 JPA다.

-> 즉, JPA는 ORM 표준 API 인터페이스이고 하이버네이트는 이를 구현한 구현체다.

3) JPA 를 사용해야 하는 이유

  • 생산성: SQL을 작성하고 결과를 매핑하는 작업을 JPA가 대신 해준다.
  • 유지보수: 요구사항 변경 및 추가시 SQL을 직접 수정하거나 매핑하는 부분에 대한 수정 범위가 줄어든다.
  • 패러다임의 불일치 해결: 위에서 설명한 상속, 연관관계, 객체 그래프, 비교 등의 패러다임 불일치 문제를 JPA가 해결해준다.
  • 성능: JPA가 앱과 DB 사이에서 다양한 성능 최적화 기회를 제공한다.
  • 데이터 접근 추상화와 벤더 독립성: 다양한 DB에 대하여 종속적이지 않은 환경을 구축할 수 있다.

0개의 댓글