대부분의 기업에서는 MyBatis 인 SQL 매퍼
를 사용한다.
하지만 최근 트랜드는 JPA
사용량이 점점 늘어나고 있는 추세이다.
(출처 : https://www.slideshare.net/dongmyo/mybatis-jpa-123381168)
IT 기업으로 유명한 우아한형제들
이나 쿠팡
등에서는 이미 JPA
를 사용하고 있다.
왜 사람들이 JPA
에 열광하는 것일까?
사실 필자의 경우에는 학원에서 처음 JPA를 접했지만,
MyBatis를 사용해 본 경험은 없어서 JPA가 편하기는 했지만 크게 와닿지는 않았다.
따라서 이번에 학습을 하면서 왜 JPA를 써야 하는지
알아 볼 예정이다.
객체와 관계형 데이터베이스
대부분 개발 언어는 객체지향 언어
를 사용한다.
데이터베이스는 대부분 관계형 DB
를 사용한다.
지금 시대는 객체
를 관계형 DB
에 저장해서 관리해야 하는 시대다.
SQL 중심적인 개발의 문제점..
CRUD의 무한 반복, 지루한 코드
마이바티스나 JDBC Template 등의 SQL 매퍼
가 등장해서 약간은 편해졌다지만
여전히 반복적인 SQL을 작성해야 한다.
패러다임의 불일치
관계형 DB
는 데이터를 잘 정규화해서 보관하는것이 목표
객체
는 속성과 기능을 잘 묶어서 캡슐화해서 사용하는 것이 목표
둘 간의 차이
가 발생한다.
객체를 관계형 DB에 반영하기 위해서는..
객체를 SQL로 변환
해서 관계형 DB에 저장해야 한다.
SQL로 변환 하는 건 누가함?
개발자
= SQL 매퍼
객체와 관계형 데이터베이스의 차이
객체와 관계형 DB는 크게 다음과 같은 차이가 있다.
- 상속
- 연관관계
상속
객체는 상속이 있지만, 관계형 DB는 상속이 없다. (그나마 유사한 슈퍼타입, 서브타입 관계가 있긴하다.)
예를 들어보자.
부모 클래스 Item
이 있고, 자식 클래스 Album, Movie, Book
이 있다고 가정하자.
Album 생성
INSERT INTO item ...
INSERT INTO album ...
Album을 생성하는건 그나마 insert 쿼리 2번으로 해결했다. 문제는 조회할 때 발생한다.
Album 조회
- Item과 Album을
JOIN
해서 결과를 만든다. - 만들어진 결과로 Album, Item의
객체를 생성
한다.
Movie를 조회하려면? 위 과정 반복해서 또 객체 생성..
연관관계
객체는 참조
를 사용 : member.getTeam() (단방향
)
테이블은 외래 키
를 사용 : JOIN ON m.team_id = t.team_id (양방향
)
객체를 테이블에 맞추어 모델링
class Member {
private Long id;
private Long teamId;
}
class Team {
private Long id;
}
이것을 가지고 Member 테이블의 INSERT 쿼리를 짤때는 쉽게 가능하다.
INSERT INTO member (member_id, team_id) VALUES ...
근데 위의 방식은 뭔가 객체지향 스럽지 않은 것 같다.
Member를 다음과 같이 수정해보자.
객체다운 모델링
class Member {
private Long id;
private Team team;
public getTeam() {
return team;
}
}
Member 테이블의 INSERT 쿼리를 보자.
INSERT INTO member (member_id, team_id) VALUES ...
team_id
를 넣어주어야 하는데 Member에는 Team을 가지고 있기 때문에 다음과 같이 넣어줄 수 있겠다.
member.getTeam().getId();
정상적으로 INSERT가 된다.
문제는 조회
할 때 발생한다.
SELECT m.*, t.* FROM member m JOIN team t ON m.team_id = t.team_id;
위처럼 member와 team을 조인한 결과를 가져온다.
그 후 Member, Team 객체에 맞게 관련 정보를 넣어 생성한다.
public Member find(Long memberId) {
// SQL 실행
Member memeber = new Member();
// DB에서 조회한 회원 관련 정보를 모두 입력
Team team = new Team();
// DB에서 조회한 팀 관련 정보를 모두 입력
member.setTeam(team);
// 회원과 팀 관계 설정
return member;
}
상당히 번거롭다.
실무에서는 이런 번거로움 때문에 SuperMemberTeam DTO
와 같은 클래스를 만들어서 사용한다.
객체답게 모델링 할수록 매핑 작업만 늘어난다.
만약, 객체를 자바 컬렉션에 넣듯이 관리한다면?
Member member = new Member();
list.add(member); // INSERT
Member findMember = list.get(memberId); // SELECT
Team team = findMember.getTeam();
상당히 편안해진다.
객체 그래프 탐색
객체는 .
을 통해 자유롭게 객체 그래프를 탐색할 수 있어야 한다.
ex) member.getTeam();
하지만 실상은 처음 실행하는 SQL에 따라 탐색 범위가 결정된다.
SELECT m.*, t.* FROM member m JOIN team t ON m.team_id = t.team_id;
member.getTeam(); // 정상 조회 됨
member.getOrder(); // null
member
와 team
만 조회했으므로 실제 member에는 order
가 있더라도 null이 되어
엔티티의 신뢰 문제
가 발생함.
엔티티 신뢰 문제
class MemberService {
...
public void process() {
Member member = memberDAO.find(memberId);
member.getTeam(); // ??
member.getOrder().getDelivery(); // ??
}
}
memberDAO.find(memberId);
에서 무슨짓을 했는지 확인하지 않고서는 엔티티를 신뢰할 수 없다
.
레이어드 아키텍쳐
는 그 다음 계층에 대해서 신뢰
를 하고 있어야 한다.
하지만 위 코드는 신뢰할 수 없다.
물리적
으로는 Service / DAO 로 쪼개져 있지만,
논리적
으로는 코드를 직접 보지 않는 이상 신뢰가 안된다.
엔티티 신뢰 문제 대안
상황에 따라 동일한 회원 조회 메서드를 여러개 만든다.
memberDAO.getMember(); // Member만 조회
memberDAO.getMemberWithTeam(); // Member와 Team 조회
memberDAO.getMemberWithOrderWithDelivery(); // Member, Order, Delivery 조회
SQL을 직접 다루게 되면
계층형 아키텍처에서 진정한 의미의 계층 분할
이 어렵다.
== 비교하기
JDBC Template을 이용하는 경우
Long memberId = 100;
Member member1 = memberDAO.getMember(memberId);
Member member2 = memberDAO.getMember(memberId);
member1 == member2; // 다르다.
class MemberDAO {
public Member getMember(Long memberId) {
String sql = "SELECT * FROM member WHERE member_id = ?";
...
// JDBC API, SQL 실행
return new Member(..);
}
}
매번 새로운 Member를 만들기 때문에 동일하지 않다
.
자바 컬렉션에서 조회하는 경우
Long memberId = 100;
Member member1 = list.getMember(memberId);
Member member2 = list.getMember(memberId);
member1 == member2; // 같다.
컬렉션에서 조회하면 참조 값이 같기 때문에 동일하다
.
정리
위의 예제에서 봤다시피, 객체답게 모델링 할수록 매핑 작업만 늘어난다.
그래서 많은 개발자들이 '객체를 자바 컬렉션에 저장 하듯이 DB에 저장할 수는 없을까?'를 고민해왔다.
그 고민의 결과가 바로 JPA
다.
참고
- 자바 ORM 표준 JPA 프로그래밍 - 기본편
'JPA' 카테고리의 다른 글
JPA 를 공부하면서 알게 된 내용 정리 1 (0) | 2022.01.26 |
---|---|
다양한 연관관계 매핑 (0) | 2020.04.09 |
연관관계 매핑 기초 (0) | 2020.04.06 |
엔티티 매핑 (0) | 2020.04.06 |
영속성 관리 - 내부 동작 방식 (0) | 2020.04.03 |
댓글