[JPA 프로그래밍] 1. JPA 소개
SQL 중심적인 개발의 문제
SQL에 의존하는 개발
관계형 데이터 베이스는 가장 대중적이고, 신뢰할 만한 안전한 데이터 저장소다. 그래서 자바로 개발하는 애플리케이션은 대부분 관계형 데이터베이스를 데이터 저장소로 사용한다.
하지만, 데이터 베이스에 데이터를 관리하려면 SQL을 사용해야 한다. 개발자들은 지루한 SQL을 계속해서 작성해야 했고, 만약 객체에 필드가 추가가 된다면, 관련된 모든 SQL에 필드를 추가해야하기 때문에 SQL에 의존적인 개발을 할 수 밖에 없었다.
패러다임의 불일치
객체 지향 프로그래밍은 추상화, 캡슐화, 정보 은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 다양한 장치들을 제공한다. 그래서 현대의 복잡한 애플리케이션은 대부분 객체 지향 언어로 개발한다.
관계형 데이터 베이스는 데이터 중심으로 구조화되어 있고, 집합적인 사고를 요구한다. 그리고 객체 지향에서 이야기하는 추상화, 상속, 다형성 같은 개념이 없다.
애플리케이션은 자바라는 객체 지향 언어로 개발하고 데이터는 관계형 데이터베이스에 저장해야 한다면, 패러다임의 불일치 문제를 개발자가 중간에서 해결해야한다. 지금부터 패러다임의 불일치로 인해서 발생하는 문제에 대해서 알아보자.
1. 상속
객체는 상속이라는 기능을 가지고 있지만, 테이블은 상속이라는 기능이 없다. 그나마 데이터 베이스 모델링에서 이야기하는 슈퍼타입 서브타입 관계를 사용하면 객체 상속과 가장 유사한 형태로 테이블을 설계할 수 있다.
- ALBUM 객체를 조회하려면 ITEM과 ALBUM 테이블을 조인해서 조회한 다음 그 결과로 ALBUM 객체를 생성해야 한다. 이렇듯 조회든 저장이든 작성해야할 코드량이 만만치 않다. 하지만 JPA를 사용한다면 상속과 관련된 패러다임의 불일치 문제를 개발자 대신 해결해준다.
2. 연관관계
객체는 참조를 사용해서 다른 객체와 연관관계를 가지고 참조에 접근해서 연관된 객체를 조회한다. 반면에 테이블은 외래 키를 사용해서 다른 테이블과 연관관계를 가지고 조인을 사용해서 연관된 테이블을 조회한다. 참조를 사용하는 객체와 외래키를 사용하는 관계형 데이터베이스 사이의 패러다임 불일치는 객체 지향 모델링을 거의 포기하게 만들 정도로 극복하기 어렵다.
- 객체는 참조가 있는 방향으로만 조회가 가능하다. member.getTeam()은 가능하지만, 반대 방향인 team.getMember()는 불가능하다. 반면 테이블은 외래 키 하나로 MEMBER JOIN TEAM도 가능하지만 TEAM JOIN MEMBER도 가능하다.
3. 객체 그래프 탐색
객체는 자유롭게 객체 그래프를 탐색할 수 있어야 한다.
하지만 SQL을 직접 다루면 처음 실행하는 SQL에 따라 객체 그래프를 어디까지 탐색할 수 있는지 정해진다. 이것은 객체 지향 개발자에겐 너무 큰 제약이다. 비즈니스 로직에 따라 사용하는 객체 그래프가 다른데 언제 끊어질지 모르는 객체 그래프를 함부로 탐색할 수는 없기 때문이다.
SELECT M.*, T.*
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
member.getTeam(); // ok
member.getOrder(); // null
4. 비교
데이터 베이스는 기본 키의 값으로 각 행을 구분한다. 반면에 객체는 동일성 비교와 동등성 비교를 한다.
- 동일성 비교(identity)는 == 비교다. 객체 인스턴스의 주소 값을 비교한다
- 동등성 비교(equality)는 equals() 메소드를 사용해 객체 내부의 값을 비교한다.
자바 진영에서는 오랜 기간 패러다임 불일치 문제를 해결하기 위한 노력을 기울여왔다. 그리고 그 결과물이 바로 JPA이다. JPA는 패러다임의 불일치 문제를 해결해주고 정교한 객체 모델링을 유지하게 도와준다.
JPA 소개
JPA (Java Persistence API)
자바 진영의 ORM 표준 기술이다. JPA는 애플리케이션과 JDBC 사이에서 동작한다.
ORM (Object Relational Mapping)
객체와 관계형 데이터베이스를 매핑한다는 뜻이다. ORM 프레임워크는 객체와 테이블을 매핑해서 패러다임의 불일치 문제를 개발자 대신 해결해준다.
- 예를 들어 ORM 프레임워크를 사용하면 객체를 데이터 베이스에 저장할 때 INSERT SQL을 직접 작성하는 것이 아니라 객체를 마치 자바 컬렉션에 저장하듯이 ORM 프레임워크에 저장하면 된다. 그러면 ORM 프레임워크가 적절한 INSERT SQL을 생성해서 데이터 베이스에 객체를 저장해준다.
JPA 소개
과거 자바 진영은 EJB라는 기술 표준을 만들었는데 그 안에는 엔티티 빈이라는 ORM 기술도 포함되어 있었다. 하지만 너무 복잡하고 기술 성숙도도 떨어졌으며 자바 엔터프라이즈 애플리케이션 서버에서만 동작했다. 이 때 하이버네이트라는 오픈소스 ORM 프레임워크가 등장했다. 훨씬 사용하기 편하고 단점도 보완해서 많은 개발자들이 사용하기 시작했다. 결국 EJB에서 하이버네이트 기반으로 새로운 자바 ORM 기술 표준을 만들어냈는데 그것이 바로 JPA이다.
JPA는 자바 ORM 기술에 대한 API 표준 명세다. 따라서 JPA를 사용하려면 JPA를 구현한 ORM 프레임워크를 선택해야 한다. 현재 JPA 2.1을 구현한 ORM 프레임워크는 하이버네이트, EclipseLink DataNucleus가 있는데 이 중에 하이버네이트가 가장 대중적이다.
JPA를 사용해야하는 이유
1. 생산성
JPA를 사용하면 자바 컬렉션에 객체를 저장하듯이 JPA에게 저장할 객체를 전달하면 된다. INSERT SQL을작성하고 JDBC API를 사용하는 지루하고 반복적인 일은 JPA가 대신 처리해준다.
jpa.persist(member); // 저장
Member member = jpa.find(memberId); // 조회
2. 유지보수
개발자가 작성해야 했던 SQL과 JDBC API 코드를 JPA가 대신 처리해주므로 유지보수해야 하는 코드의 수가 줄어든다.
3. 패러다임의 불일치 해결
JPA는 상속, 연관관계, 객체 그래프 탐색, 비교하기와 같은 패러다임의 불일치 문제를 해결해준다.
4. 성능
JPA는 애플리케이션과 데이터베이스 사이에서 다양한 성능 최적화 기회를 제공한다.
String memberId = "helloId";
Member member1 = jpa.find(memberId);
Member member2 = jpa.find(memberId);
같은 트랙잭션 안에서 같은 회원을 두 번 조회하는 코드의 일부분이다. JDBC API를 사용해서 해당 코드를 작성했다면 회원을 조회할 때마다 INSERT SQL을 사용해서 데이터베이스와 두 번 통신을 한다. 하지만 JPA를 사용하면 회원을 조회하는 SELECT SQL을 한 번만 데이터베이스에 전달하고 두 번째는 조회한 회원 객체를 재사용한다.