파게로그
Why JPA? 본문
SK Planet에서 제공하는 김영한 강사님의 강의를 참고했다.
T아카데미(https://tacademy.skplanet.com/live/player/onlineLectureDetail.action?seq=149)
YouTube(https://www.youtube.com/watch?v=WfrSN9Z7MiA&list=PL9mhQYIlKEhfpMVndI23RwWTL9-VL-B7U)
간단하게 요약하자면, JPA를 통해서 객체지향 프로그래밍과 관계형 데이터베이스라는, 서로 다른 패러다임의 간극을 메꿀 수 있다. 객체지향적으로 프로그램을 설계할 수록 SQL 쿼리는 보다 복잡해지는데 이를 ORM을 통해서 해결할 수 있는 것이다.
Member와 Team이라는 객체, 그리고 동일한 이름의 테이블이 있다고 생각해보자.
ORM을 사용함으로써, 첫째로 SQL에 의존적인 개발로부터 탈피할 수 있다. Member 클래스에 필드를 추가할 때마다 SQL문의 INSERT, SELECT, UPDATE 절을 모두 수정해야 하는 불편함을 없앨 수 있다. 둘째로 엔티티 신뢰 문제를 해결할 수 있다. 예를 들어, member.getTeam()을 구현할 수 없는 것은 아니다. 헌데, 이러한 코드를 사용하는 사람 입장에서는 해당 코드가 정상적으로 작동하는지 또는 작동하지 않는지에 대해 확신할 수 없다. 왜냐하면 해당 코드가 작동하기 위해서는 memberDao가 member가 속한 team을 획득할 수 있도록 직접 구현되어 있어야 하기 때문이다. 셋째로 계층 분할을 통해 진정한 계층형 아키텍처의 구축이 가능하다.
이는 곧 객체지향 프로그래밍과 관계형 데이터베이스라는, 패러다임의 불일치에서 기인한다. 구체적으로는, 상속과 관련하여, 다음과 같은 문제가 있다.
OOP에서는 객체 간의 상속 관계로, DB에서 슈퍼타입과 서브타입 관계로 표현할 것이다. 반면 RDB는 기본적으로는 상속을 지원하지 않기 때문에, Member를 저장하기 위해서는, 객체 분해 → INSERT INTO TEAM... → INSERT INTO MEMBER... 이러한 형식으로 INSERT문을 2번 사용해야 한다. 게다가 조회를 위해서는, Item과 Book을 JOIN하면 되기는 하지만, Book 말고 다른게 있으면, 모든 쿼리를 각각 작성해야 한다.
그래서 DB에 저장할 객체는, 객체를 테이블에 맞추어 모델링하고자, 상속 관계를 사용하지 않는다. 즉 다음과 같이 FK를 그대로 매핑해버림으로써 INSERT INTO MEMBER(MEMBER_ID, TEAM_ID, USERNAME) VALUES ...와 같이 바로 쿼리를 작성할 수 있다.
class Member {
String id;
Long teamId;
String username;
}
class Team {
Long id;
String name;
}
하지만 객체지향 프로그래밍 설계를 충분히 따르면 다음과 같은 구조가 되어야 한다.
class Member {
String id;
Team team;
String username;
Team getTeam() {
return team;
}
}
class Team {
Long id;
String name;
}
하지만 위와 같이 설계하면, INSERT INTO MEMBER(MEMBER_ID, TEAM_ID, USERNAME) VALUES ... 에서
member.getTeam().getId()로 불러와야 한다.
조회를 하게 되면 문제는 더 커진다.
public Member find(String memberId) {
// SQL 실행
// SELECT M.*, T.*
// FROM MEMBER M
// JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
Member member = new Member();
// member set...
Team team = new Team();
// team set...
member.setTeam(team);
return member;
}
이렇게 해서 반환하게 되면, 코드가 너무 길어진다. 그리고 객체는 자유롭게 객체 그래프를 탐색할 수 있어야 하지만, 처음 실행하는 SQL문에 따라 탐색 범위가 결정되어버린다. 즉 아래와 같은 코드의 결과를 알고자 한다면 memberDao를 직접 확인해야만 하는 것이다.
member.getTeam(); // OK
member.getOrder(); // null
결국 memberDao에서는, 동일한 member를 조회하기 위해 메서드를 여러 개 생성해야 하는 것이다.
memberDao.getMember();
memberDao.getMemberWithTeam();
memberDao.getMemberWithOrderWithDelivery();
...
연관관계와 관련하여, 다음과 같은 가장 큰 차이점으로 정리해볼 수 있다.
객체는 참조를 사용: member.getTeam() → 단방향
테이블은 외래 키를 사용: JOIN ON M.TEAM_ID = T.TEAM_ID → 양방향
JPA의 역사
JPA와 관련하여 EJB(Enterprise Java Beans) - Hibernate(open source framework) - JPA(Java standard) 순서로 개발되었다. 실제로 우리가 인식하기로는, 인터페이스만 존재하는 JPA의 구현체가 Hibernate이다.
JPA의 장점
SQL 중심적인 개발에서, 객체 중심적인 개발로의 전환
높은 생산성
유지보수의 용이성
패러다임 불일치의 해결
캐시 등을 통한 성능 유지
데이터 접근 추상화와 벤더 독립성
표준화
'콤퓨타 왕기초 > JPA' 카테고리의 다른 글
JPA 내부 구조 (0) | 2021.06.02 |
---|---|
연관관계 매핑 (0) | 2021.05.28 |
실습 3 (Mapping annotations) (0) | 2021.05.27 |
[실습] Mapping to DDL (0) | 2021.05.27 |
[실습] JPA in Maven project (0) | 2021.05.27 |