JPA(Java Persistence API) : Java 에서 ORM(Object-Relational Mapping) 기술 표준으로 사용되는 인터페이스 모음
애플리케이션의 Class 와 RDB(Relational DB)의 테이블을 매핑한다는 뜻이다.
= 기술적으로 애플리케이션의 객체를 RDB 테이블에 영속화 해줌
Java 진영에서 ORM(Object-Relational Mapping) 기술 표준으로 사용하는 인터페이스 모음
자바 어플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스
인터페이스 이기 때문에 Hibernate, OpenJPA 등이 JPA를 구현함
왜 JPA 를 쓰는가?
JPA와 모던 자바 데이터 저장기술
애플리케이션 객체 지향 언어 + 관계형 DB 에서 객체를 영구 보관하는
다양한 저장소(RDB, _NoSQL, File 등)가 존재하지만 현실적인 대안은 관계형 DB이다.
객체를 관계형 DB에 저장해 관리하는 것이 중요해짐
관계형 DB를 사용하려면 SQL을 짤 수 밖에 없다 = SQL에 의존적인 개발
But!!! SQL 중심 개발에는 여러 문제가 있음
SQL 중심 개발의 문제점
CRUD 의 반복
자바 객체와 SQL 의 변환하는 과정의 반복
Ex)
회원에 이름 정보를 추가해보자
Member 클래스에 private int name 을 선언하고
INSERT, SELECT, UPDATE 등 관련된 쿼리에 name 정보를 추가
호출도 반대의 과정이 필요
객체지향
추상화, 캡슐화, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 서비스 제공
RDB
데이터를 잘 정규화해서 보관, 관리하는 것이 목표
결국 패러다임이 다른 두 가지를 가지고 억지로 매핑하기 때문에 여러 문제가 생김
JPA를 사용하여 얻을 수 있는 가장 큰 것은 SQL아닌 객체 중심으로 개발할 수 있다는 것이다. 이에 따라 당연히 생산성이 좋아지고 유지보수도 수월하다. 또한 JPA는 패러다임의 불일치도해결하였다. 예를 들면 JAVA에서는 부모클래스와 자식클래스의 관계 즉, 상속관계가 존재하는데 데이터베이스에서는 이러한 객체의 상속관계를 지원하지 않는다(상속 기능을 지원하는 DB도 있지만 객체 상속과는 다름). 이런 상속관계를 JPA는 아래와 같은 방식으로 해결하였다.
Object : 상속 있음
RDB : 상속 없음 - 유사한 물리 모델로, 슈퍼-서브 타입 관계가 존재
출처 : 자바 ORM 표준 프로그래밍
Album 객체를 DB에 저장해보자
a. 객체 분해 (Album 객체는 Item의 속성을 모두 가짐)
b. 각각 다른 테이블에 대한 INSERT 쿼리 두 번 작성
INSERT INTO ITEM ...
INSERT INTO ALBUM ...
Album 을 조회하는 과정 (얘가 에바임)
a. 각각의 테이블에 따른 Join SQL 작성 -> Item 과 Album 을 Join 해서 데이터를 가져옴
b. 각각의 객체를 생성하고 모든 필드 값을 세팅 -> Item 과 Album 각각 모든 필드값을 세팅
c. Movie, Book 을 조회하고 싶으면 위의 과정을 다시 반복 -> DB에 저장할 객체에는 상속을 이용하지 않아서 발생하는 문제
자바 컬렉션에 저장하기
a. 저장 : list.add(album);
b. 조회 : Album album = list.get(albumId);
c. 다형성 활용 : Item item = list.get(albumId);
자바의 컬렉션에 저장하면 단순한 작업이 RDB를 거치는 순간 번거로운 매핑 작업을 해야함
Object
a. Reference 를 사용하여 연관 관계를 찾음 - member.getTeam();
b. 단방향으로만 관계가 존재 - Member -> Team 은 가능하지만 반대는 불가능
RDB
a. 외래키, join 쿼리를 통해 연관 관계를 찾음 - JOIN ON M.TEAM_ID = T.TEAM_ID
b. 양방향으로 모두 조회 -> 단방향 존재 x
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 컬럼 사용
}
ㄴ 객체지향 모델링
INSERT INTO MEMBER(MEMBER_ID, TEAM_ID, USERNAME) VALUES ...
Member 객체를 조회하기 위해서는
a. MEMBER 와 TEAM 을 JOIN 해서 데이터를 한 번에 모두 가져온다.
b. MEMBER 와 TEAM 에 개한 값을 각각 세팅한다.
c. member.setTeam(team); rhk rkxdl wlrwjq dusrhks rhksrPfmf aowdjwnsek.
d. 해당 member 객체를 반환한다.
=> 데이터 조회의 복잡성
자바컬렉션에서 관리하면 조회의 복잡성을 사라지지만 관리의 효율이 떨어지게 된다.
객체는 자유롭게 객체 그래프를 탐색할 수 있어야 하지만 서비스 로직에서 RDB와 연결된 데이터를 탐색할 때 객체 그래프를 탐색할 수 없다.
Cuz - SQL 탐색은 범위가 결정되어있기 때문
ex) MEMBER 테이블을 가져왔다면 TEAM 테이블을 가져오지 않았기에 TEAM 데이터는 NULL 이다.
위 현상은 Entity 신뢰의 문제로 이어지는데 예를 들어 내가 만든 서비스 로직에 다른 사람이 사용하고자 하면 DAO에서 반환한 엔티티가 어떤 값인지 직관적으로 알 수 없다.
이와 같이 계층형 아키텍쳐(Layered 아키텍처)에서는 계층간의 신뢰가 필요한데 엔티티를 신뢰할 수 없는 문제가 발생하기 때문에 문제가 생길 수 있다.