JPA 개요
- 기존에는 JDBC API를 통해 직접 SQL문을 작성하였다.
- 비지니스 로직보다 SQL 과 JDBC API를 작성하는 데 더 많은 시간을 보냈다.
- Mybatis, JdbcTemplate 같은 Mapper를 이용하여 줄였지만 여전히 등록, 수정, 삭제, 조회 SQL문은 작성해야 한다.
- 패러다임의 불일치 발생 : 관계형 데이터 베이스 != 객체 지향 프로그래밍 언어
- ORM 프레임워크 : 객체와 관계형 데이터베이스를 맵핑, ORM을 사용할 경우 DBMS 벤더 마다 다른 SQL의 종속성을 줄이고 호환성 향상이 가능
- Hibernate : 오픈소스 ORM 프레임워크
- JPA : Hibernate 기반 새로운 자바 ORM 기술이 JPA
SQL 문을 직접 다룰 때 발생하는 문제점
반복
1
2
3
4
public class Member {
private String memberId;
private String name;
}
- member 에 대한 기능을 구현할 경우
- 조회 :
1
SELECT MEMBER_ID , NAME FROM MEMBER M WHERE MEMBER_ID = ?
1
stmt.executeQuery(sql);
- 등록 :
1
INSERT INTO MEMBER VALUES (?,?);
1
pstmt.executeQuery(sql);
- 조회 :
- 등등 객체마다 SQL 과 JDBC API를 사용해서 변환 작업을 반복적으로 해주어야 한다.
의존적인 개발 - 1
1
2
3
4
5
public class Member {
private String memberId;
private String name;
private String email;
}
- member 의 요구사항 변경으로 email 을 추가할 경우
- 조회 :
1
SELECT MEMBER_ID , NAME , EMAIL FROM MEMBER M WHERE MEMBER_ID = ?
- 등록 :
1
INSERT INTO MEMBER VALUES (?,?,?);
- 조회 :
- 등등 모든 기능마다 SQL문을 수정해주어야 한다.
의존적인 개발 - 2
1
2
3
4
5
6
7
8
9
public class Member {
private String memberId;
private String name;
private Team team;
}
public class Team {
private String teamName;
}
- member 에 연관된 테이블 team 이 추가될 경우
- 조회 :
1
SELECT * FROM MEMBER M JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
- 조회 :
- 이역시 SQL문을 수정해주어야 한다.
이렇게 될경우 SQL에 의존적인 개발을 해야하기 때문에 엔티티를 신뢰하고 사용할 수 없다.
JPA 와 문제 해결
- JPA는 다음과 같은 문제를 JPA에서 제공하는 API를 통해 해결할 수 있다.
- 개발자는 이를 통해 직접 SQL을 작성하지 않고 적절한 SQL 을 생성하여 데이터베이스에 전달한다.
- CRUD API 예시
- 저장 :
1
jpa.persist(member);
- 조회 :
1
jpa.find(Member.class,memberId);
- 수정 :
1 2
Member member = jpa.find(Member.class,memberId); member.setName(name);
- 연관된 객체 조회 :
1 2
Member member = jpa.find(Member.class,memberId); Team team = member.getTeam();
- 저장 :
패러타임 불일치
- java 와 관계형 데이터 베이스는 지향하는 목적이 서로 다르기 때문에 표현방법이 다르다.
- 그렇기에 발생하는 패러다임의 불일치 문제를 해결하기 위해 Jpa 는 아래와 같이 해결한다.
상속
- 객체에는 상속 개념이 존재한다.
- 하지만 데이터베이스에는 상속이라는 개념이 없다. 유사한 형태로 아래와 같이 테이블을 설계할 수 있다.
- 위와 같이 item을 상속하는 Album, Movie, Book 이 있다고 가정할 경우
- Album 객체를 저장할 경우
- 저장 :
1 2
INSERT INTO ITEM ... INSERT INTO ALBUM ...
- 저장 :
- Movie, Book 객체도 마찬가지로 부모 타입을 저장하고 자식 타입을 저장하여야 한다.
상속 - JPA
- JPA는 상속과 관련된 패러다임의 불일치 문제를 개발자 대신 해결해준다. 자바 컬렉션에 객체를 저장하듯이 JPA 에게 객체를 저장하면 된다.
- 예시
- 저장 :
1
jpa.persist(album);
- 조회 :
1
Album album = jpa.find(Album.class,albumId)
- 저장 :
연관관계
- 객체는 참조를 사용해서 다른 객체와 연관관계를 가지고 참조에 접근해서 연관된 객체를 조회한다.
- 반면에 테이블은 외래 키를 사용해서 다른 테이블과 연관관계를 가지고 조인을 사용해서 연관된 테이블을 조회한다.
1
2
3
4
5
6
7
8
9
10
class Member {
private String id;
private Long teamId;
private String username;
}
class Team {
private Long id;
private String name;
}
- 만약 위와 같이 객체를 테이블에 맞추어 모델링하면 저장과 조회는 편리하다. 하지만 객체관점으로 봤을때 teamId 만으로 Team 객체에 대한 정보를 알수없다. 이는 좋은 객체 모델링은 기대하기 어렵고 결국 객체지향의 특징을 잃어버리게 된다.
1
2
3
4
5
class Member {
private String id;
private Team team;
private String username;
}
- 그렇다고 객체 관점에서 모델링을 했을 경우 객체를 테이블에 저장하거나 조회하기가 쉽지 않다.
연관관계 - JPA
- JPA는 연관관계 패러다임 불일치 문제를 해결해준다.
- 예시
- 저장
1 2
member.setTeam(team); //회원과 팀 연관관계 설정 jpa.persist(member); //회원과 연관관계 함께 저장
- 개발자는 회원과 팀의 관계를 설정하고 회원 객체를 저장하면 된다.
- 조회
1 2
Member member = jpa.find(Member.class,memberId); Team team = member.getTeam();
- 저장
객체 그래프 탐색
- 위와 같이 객체 연관관계로 설계되어 있다고 가정해보자.
1
2
3
SELECT M.*, T.*
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
- 위와 같이 SQL문이 있을 때
member.getTeam()
의 경우 동작하지만member.getOrder()
의 경우 동작하지 않는다.- 즉, SQL을 직접 다루면 처음 실행하는 SQL문에 따라 객체 그래프를 어디까지 탐색 가능한지 정해진다.
객체 그래프 탐색 - JPA
- JPA를 사용하면 객체 그래프를 마음껏 탐색할 수 있다.
- 예시
- 조회 :
1
member.getOrder.getOrderItem()
- 조회 :