JPA란? 예전부터 흥했던 Java 진영 ORM 기술 표준입니다. 많은 사람들이 JPA를 사용하고 있고 이제야 저 처럼 공부하시는 분들도 있으십니다. JPA란 무엇인지 정리하고 제가 아는 지식을 공유를 하도록 하겠습니다.
JPA를 딱 요약하자면 다음과 같습니다.
- 객체지향과 관계형 데이터베이스의 패러다임 불일치 해소
- 특정 DB에 종속되지 않는 독립성
- 성능 최적화
- 네이티브쿼리 실행 가능, Mybatis같은 따른 모듈과 연동 가능
패러다임 불일치
상속
객체는 상속이라는 개념이 있습니다. 하지만 테이블은 상속이라는 개념이 없죠. 그래서 상속형태의 객체들을 테이블로 그려야 한다면 좀 귀챃은 작업이 되곤 했습니다. 또는 DB모델링이 완료된 후 그것 기반으로 객체를 모델링 하곤 했죠.일반적으로 상속된 객체에 대해서 INSERT할 경우 먼저 부모테이블에 데이터를 먼저 INERT한 후 INSERT된 데이터를 조회하고 부모의 키와 데이터를 현재 INSERT할 테이블의 타입 및 정보들과 같이 INSERT해야 합니다. 코드량이 만만치 않겟죠, 또한 조회시 부모의 테이블과 조회할 테이블을 조인걸어서 가져와야 합니다.
하지만 JPA를 쓰면 Collection객체에 add(), remove(), getXXX(), 하듯이 사용 할 수 있습니다.
연관관계
객체는 참조를 통해서 다른 객체와의 연관관계를 가지며 이 참조를 통해서 해당 객체를 조회 할 수 있습니다. 하지만 테이블은 외래키라고 하는 키를 통해서 연관관계를 가지며 조인에서 이 키를 통해서 연관된 테이블을 조회 할 수 있습니다.일반적으로 외래키를 통해 연관관계를 맺고 있기 때문에 왜래키를 통해서 데이터를 가져올 수 밖에 없습니다. 그러다 보니 이런 외래키를 저장하고 관리할 뿐 연관된 객체를 직접적으로 가져오거나 쓸 수 가 없습니다.
하지만 JPA를 쓰면 이런 키를 관리하는 것이 아니라 getXXX()를 통해서 연관된 객체를 구하거나 사용 할 수 있습니다.
객체 그래프 탐색
일반적으로 어떤 쿼리를 만드느냐에 따라서 현재 객체가 탐색할 수 있는 범위가 결정이 납니다. 예를 들어 Member테이블과 Group테이블만을 가져오는 쿼리를 통해 생성된 객체는 Group과 연관된 Tag라는 객체를 구할 수 없습니다. 오직 Member와 Group만의 데이터를 탐색하고 사용할 수 있게 됩니다.하지만 JPA를 사용하면 연관관계에 있는 모든 객체를 탐색하고 조회하고 사용할 수 있습니다.
비교
일반적으로 서비스구역에서 getMember()는 아래와 같이 구현이 됩니다.public Member getMember(String memberId) {
String sql = "SELECT * FROM MEMBER ID = ?";
...
return new Member(...);
}
...
Member member1 = memberDao.getMember("01");
Member member2 = memberDao.getMember("01");
member1 == member2; //틀림
동일한 데이터를 가지고 구현은 했지만 Dao에서 new Member()를 통해서 데이터를 넘겨주기 때문에 둘은 다른 인스턴스이기 때문입니다. 하지만 JPA에서는 아래와 같이 같은 로우를 조회시마다 같은 인스턴스를 반환하도록 할 수 있습니다.
Member member1 = jpa.find(Member.class, "01");
Member member2 = jpa.find(Member.class, "01");
member1 == member2; //같음
잠깐 이야기하자면 영속성 컨텍스트에서 객체를 캐쉬처럼 보관해서 반환하기 때문에 같을 수가 있습니다. 이것은 차후에 자세히 설명 하도록 하겠습니다.
DB 독립성
혹시 여러분은 MYSQL을 사용하시다가 갑자기 ORACLE로 변경해본적이 있으신가요? 아니면 반대로 ORACLE에서 MYSQL로 변경해 본적이 있으신가요? 각자 밴더사마다의 SQL은 특성이 있습니다. SQL은 거의 비슷합니다. 하지만 둘의 틀린점도 존재하기 마련이죠.만약 엔터프라이즈급 서비스가 있습니다. 여기엔 무수히 많은 비지니스 로직과 쿼리들이 존재해 있죠. 또한 ORACLE로 개발이 되어 있었습니다. 어느날 갑자기 B사에 납품을 해야하는데 여긴 정책상 MYSQL로 가야한다고 했습니다.
음... 밤을 새워가면서 MYSQL로 모든 쿼리를 변경해야 했을 뿐만 아니라 제공해주지 않는 기능으로 인해서 비지니스 로직을 수정해야 했습니다. 또한 테스트 시에 문제도 발생해서 테스트, 수정, 테스트, 수정 하느라 진땀을 뺀적이 있었죠.
하지만 JPA를 사용하게 되면 이런 특정 DB 벤더사에 종속되는 문제를 해결해줍니다. 정의된 로직을 보고 쿼리를 새로 생성해주기 때문이죠. 만약 DB벤더사에 종속되지 않는 서비스를 개발해야 한다면 JPA를 쓰시기 바랍니다. 아니면 벤더사마다 쿼리를 만드셔야 하는 뼈아픈 작업이 기다립니다.
성능최적화
한번 조회한 쿼리는 내용이 변경되지 않는한 동일 쿼리를 조회시 기존에 조회된 데이터를 반환합니다. 이 역할은 1차 캐쉬라고도 부르는데요. 이것은 영속성 컨텍스트에서 객체를 관리하기 때문에 가능한 것입니다. 일반적으로 쿼리를 호출 할 때마다 DB에 쿼리를 날려서 데이터를 가져오고 데이터를 객체로 변환하고 그리고 객체를 반환하는데 1차 캐쉬는 동일한 쿼리를 호출하는 로직이라면 DB에 조회를 하지 않고 영속성 컨텍스트에 담겻던 객체를 반환 합니다. DB를 호출하지 않으니 별도 비용이 들지 않기 때문에 성능상에서 유리 합니다.네이티브 쿼리 실행
통계같은 복잡한 쿼리 같은 경우 진심 직접 SQL을 작성하는 것이 더 쉽고 빠를 수 있습니다. 직접 이런 쿼리를 쓸수 있도록 제공을 해주고 있습니다. 또는 Mybatis나 JdbcTemplate를 혼용해서 쓸수 도 있습니다.정리
정리하면 JPA를 쓰게 되면 개발자는 직접 쿼리를 거의 작성을 안하게 됩니다. 또한 객체지향적인 방법으로 개발을 할 수 있게 됩니다. 예전에는 우리나라에서는 Mybatis로 대부분 개발을 했지만 점차적으로 JPA를 점점 더 많이 사용하고 있습니다. 예전에는 Java객체지향적인 개발 보다 DBA쪽 모델링이 먼저 우선시 되었다고 생각이 듭니다. 그래서 DB 모델링 작업이 완료되고 나서야 개발을 시작했기 때문이였죠.또한 어떤것이 좋다고 이야긴 할 수 없습니다. Mybatis를 사용할지 JPA를 사용할지를 결정하는 것은 상황에 따라서 틀릴 수 있습니다. 결국 결정하는 것은 저 윗선에서 결정을 하게 됩니다. 만약에 여러분들에게 선택 기회가 주어진다면 그것은 스스로의 판단에 맡기도록 하겠습니다.
하지만 좋은 기술이라도 제대로 모르고 사용하면 독이 됩니다. 실제 영속성 컨텍스트나 JPA의 중요한 것을 모르고 개발하면 많은 문제가 발생 할 수 있습니다. 그러니 저도, 여러분도 열심히 공부하고 공부해서 잘 사용 했으면 합니다.
COMMENTS