1. JPA 소개

728x90

T아카데미에서 김영한님의 JPA 강의를 수강하였고, JPA에 큰 관심을 두게되었다. 그래서 모 개발자의 '자바 ORM 표준 JPA 프로그래밍' 책을 공부하면서 정리하기로 하였다. 

 

우리는 어떤 프로젝트를 진행할 때, 어떤 데이터를 저장하고 조회해야하는 경우가 잦다. 데이터 베이스에는 관계형 데이터 베이스(RDB)와 최근에는(최근이라는 표현이 맞는지는 잘 모르겠다) No SQL이라 불리는 비관계형 데이터 베이스 또한 많이 쓰이고있다. (No SQL은 직접 공부해본적이 없어서 잘 모르겠지만) 관계형 데이터베이스는 가장 대중적이고 신뢰할 만한 안전한 데이터 저장소다. 그래서 자바로 개발하는 애플리케이션은 대부분 관계형 데이터베이스를 데이터 저장소로 사용한다. 

데이터 베이스를 관리하려면 SQL을 사용해야 한다. 자바로 작성한 애플리케이션은 JDBC API를 사용해서 SQL을 데이터베이스에 전달하는데, 자바 서버 개발자들에게 이것은 너무나 당연한 이야기이며 SQL도 잘 다룬다. 

하지만 실제 개발 업무를 하다보면 이 SQL을 다루는 일은 문제점이 있다. 

  • 진정한 의미의 계층 분할이 어렵다.

  • 엔티티를 신뢰할 수 없다.

  • SQL에 의존적인 개발을 피하기 어렵다.

 

JPA와 문제 해결

이제부터 소개할 JPA는 이러한 문제를 해결할 수 있다. 그렇다면 어떻게 해결하는 것일까?

JPA를 사용하면 객체를 데이터베이스에 저장하고 관리할 때, 개발자가 직접 SQL을 작성하는 것이 아니라 JPA가 제공하는 API를 사용하면 된다. 그러면 JPA가 개발자 대신에 적절한 SQL을 생성해서 데이터베이스에 전달한다. 

조회 기능 

ex) Member member = jpa.find(Member.class, memberId);  // 조회 

find() 메서드는 객체 하나를 데이터베이스에서 조회한다. JPA는 객체와 매핑정보를 보고 적절한 SELECT SQL을 생성해서 데이터베이스에 전달하고 그 결과로 Member 객체를 생성해서 반환한다. 

수정 기능

ex) Member member = jpa.find(Member.class, memberId);
member.setName("이름변경"); // 수정

JPA는 별도의 수정 메서드를 제공하지 않는다. 대신에 객체를 조회해서 값을 변경만 하면 트랜잭션을 커밋할 때 데이터베이스에 적절한 UPDATE SQL이 전달된다. 

연관된 객체 조회

ex) Member member = jpa.find(Member.class, memberId);
Team team = member.getTeam(); // 연관된 객체 조회 

JPA는 연관된 객체를 사용하는 시점에 적절한 SELECT SQL을 실행한다. 따라서 JPA를 사용하면 연관된 객체를 마음껏 조회할 수 있다.

지금까지 JPA의 CRUD API를 간략히 살펴보았다. 수정 기능과 연관된 객체 조회에서 설명한 것처럼 JPA는 SQL을 개발자 대신 작성해서 실행해주는 것 이상의 기능들을 제공한다. 

 

패러다임의 불일치 

객체지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 다양한 장치들을 제공한다. 그래서 현대의 복잡한 애플리케이션은 대부분 객체지향 언어로 개발한다. 

비즈니스 요구사항을 정의한 도메인 모델도 객체로 모델링하면 객체지향 언어가 가진 장점들을 활용할 수 있다. 하지만 이렇게 정의한 도메인 모델을 저장할 때 발생하는데,  자바 내에서 이러한 객체를 파일로 저장하고 저장된 파일을 다시 객체로 바꾸는 기능이 있음에도 여러가지 상황적인 요소에 의해서 현실성이 없다. 결국  관계형 데이터 베이스에 객체를 저장하는 것이 현실적인 대안인데 이는 또 다른 문제점을 야기한다. 관계형 데이터 베이스는 데이터 중심으로 구조화되어 있고, 집합적인 사고를 요구한다. 그리고 객체지향에서 이야기하는 추상화, 상속, 다형성 같은 개념이 없다. 

객체와 관계형 데이터 베이스는 지향점이 다르므로 둘의 기능과 표현 방법도 다르다. 이것을 객체와 관계형 데이터베이스의 패러다임 불일치 문제라한다. 따라서 객체 구조를 테이블 구조에 저장하는 데는 한계가 있다. 

애플리케이션은 자바라는 객체지향 언어로 개발하고 데이터는 관계형 데이터베이스에 저장해야 한다면 패러다임의 불일치 문제를 개발자가 중간에서 해결해야 한다. 문제는 이런 객체와 관계형 데이터베이스 사이의 패러다임 불일치 문제를 해결하는 데 너무 많은 시간과 코드를 소비하는 데 있다. 

어찌됐건 패러다임의 불일치 문제를 해결하기 위해 데이터베이스의 같은 row를 조회할 때마다 같은 인스턴스를 반환하도록 구현하는 것은쉽지 않다. 게다가 여기에 여러 트랜잭션이 동시에 실행되는 상황까지 고려하면 문제는 더 어려워진다. 

 

JPA와 비교

JPA는 같은 트랜잭션일 때 같은 객체가 조회되는 것을 보장한다. 그러므로 다음 코드에서 member1과 member2는 동일성 비교에 성공한다.

String memberId = "100";
Member member1 = jpa.find(Member.class, memberId);
Member member2 = jpa.find(Member.class, memberId);

member1 == member2; // true (JDBC 통해서 member1, 2를 조회하게되면 이 값이 false가 나온다)

객체 비교하기는 분산 환경이나 트랜잭션이 다른 상황까지 고려하면 더 복잡해진다.

 

정리

객체 모델과 관계형 데이터베이스 모델은 지향하는 패러다임이 서로 다르다. 문제는 이 패러다임의 차이를 극복하려고 개발자가 너무 많은 시간과 코드를 소비한다는 점이다. 더 어려운 문제는 객체지향 애플리케이션답게 정교한 객체 모델링을 하면 할수록 패러다임의 불일치 문제가 더 커진다는 점이다. 그리고 이 틈을 메우기 위해 개발자가 소모해야 하는 비용도 점점 더 많아진다. 결국, 객체 모델링은 힘을 잃고 점점 데이터 중심의 모델로 변해간다. 

자바 진영에서는 오랜 기간 이 문제에 대한 숙제를 안고 있었고, 패러다임의 불일치 문제를 해결하기 위해 많은 노력을 기울여왔다. 그리고 그 결과물이 바로 JPA다. JPA는 패러다임의 불일치 문제를 해결해주고 정교한 객체 모델링을 유지하게 도와준다. 

 

JPA란 무엇인가? 

JPA(Java Persistence API)는 자바 진영ORM 기술 표준이다. JPA는 아래의 그림처럼 애플리케이션과

JPA

JDBC 사이에서 동작한다. 

 

그렇다면 ORM이란 무엇일까? ORM(Object-Relation Mapping)은 이름 그대로 객체와 관계형 데이터베이스를 매핑한다는 뜻이다. ORM 프레임워크는 객체와 테이블을 매핑해서 패러다임의 불일치 문제를 개발자 대신 해결해준다. ORM 프레임워크는 객체와 테이블을 매핑해서 패러다임의 불일치 문제를 개발자 대신 해결해준다. 예를 들어 ORM 프레임워크를 사용하면 객체를 데이터베이스에 저장할 때 INSERT SQL을 직접 작성하는 것이 아니라 객체를 마치 자바 컬렉션에 저장하듯이 ORM 프레임워크에 저장하면 된다. 그러면  ORM 프레임워크가 적절한 INSERT SQL을 생성해서 데이터베이스에 객체를 저장해준다. 

JPA를 사용해서 객체를 저장하는 코드는 다음과 같다.

jpa.persist(member); //저장

조회할 때도 JPA를 통해 객체를 직접 조회하면 된다. 

JPA를 사용해서 객체를 조회하는 코드는 다음과 같다 

Member member = jpa.find(memberId); //조회

 

ORM 프레임워크는 단순히 SQL을 개발자 대신 생성해서 데이터베이스에 전달해주는 것뿐만 아니라 앞서 이야기한 다양한 패러다임의 불일치 문제들도 해결해준다. 따라서 객체 측면에서는 정교한 객체 모델링을 할 수 있고 관계형 데이터베이스는 데이터베이스에 맞도록 모델링하면 된다. 그리고 둘을 어떻게 매핑해야 하는지 매핑 방법만 ORM 프레임워크에게 알려주면 된다. 덕분에 개발자는 데이터 중심인 관계형 데이터베이스를 사용해도 객체지향 애플리케이션 개발에 집중할 수 있다. 

어느 정도 성숙한 객체지향 언어에는 대부분 ORM 프레임워크들이 있는 각 프레임워크의 성숙도에 따라 단순히 객체 하나를 CRUD하는 정도의 기능만 제공하는 것부터 패러다임 불일치 문제를 해결해주는 ORM 프레임워크도 있다. 자바 진영에도 다양한 ORM 프레임워크들이 있는데 그중에 하이버네이트 프레임워크가 가장 많이 사용된다. 하이버네이트는 거의 대부분의 패러다임 불일치 문제를 해결해주는 성숙한 ORM 프레임워크다. 

JPA 소개 

과거 자바 진영은 엔터프라이즈 자바 빈즈(EJB)라는 기술 표준을 만들었는데 그 안에는 엔티티 빈이라는 ORM 기술도 포함되어 있었다. 하지만 너부 복잡하고 기술 성숙도도 떨어졌으며 자바 엔터프라이즈(J2EE) 애플리케이션 서버에서만 동작했다. 이때 하이버네이트라는 오픈소스 ORM 프레임워크가 등장했는데 EJB의 ORM 기술과 비교해서 가볍고 실용적인데다 기술 성숙도도 높았다. 또한 자바 엔터프라이즈 애플리케이션 서버 없이도 동작해서 많은 개발자가 사용하기 시작했다. 결국 EJB 3.0에서 하이버네이트를 기반으로 새로운 자바 ORM 기술 표준이 만들어졌는데 이것이 바로 JPA다. 

 

위의 그림처럼 JPA는 자바 ORM 기술에 대한 API 표준 명세다. 쉽게 이야기하면 인터페이스를 모아둔 것이다. 따라서 JPA를 사용하려면 JPA를 구현한 ORM 프레임워크를 선택해야 한다. 이 JPA를 구현한 ORM 프레임워크는 하이버네이트, EclipseLink, DataNucleus가 있는데 이 중에 하이버네이트가 가장 대중적이다. 

JPA라는 표준 덕분에 특정 구현 기술에 대한 의존도를 줄일 수 있고 다른 구현 기술로 손쉽게 이동할 수 있는 장점이 있다. 그리고 JPA 표준은 일반적이고 공통적인 기능의 모음이다. 따라서 표준을 먼저 이해하고 필요에 따라 JPA 구현체가 제공하는 고유의 기능을 알아가면 된다. 

 

왜 JPA를 사용해야 하는가?

JPA를 사용해야 하는 이유를 나열해본다. 

생산성

JPA를 사용하면 다음 코드처럼 자바 컬렉션에 객체를 저장하듯이 JPA에게 저장할 객체를 전달하면 된다. SQL을 작성하고 JDBC, API를 사용하는 지루하고 반복적인 일은 JPA가 대신 처리해준다. 

jpa.persist(member); //저장
Member member = jpa.find(memberId); //조회

따라서 지루하고 반복적인 코드와 CRUD용 SQL을 개발자가 직접 작성하지 않아도 된다. 더 나아가서 JPA에는 CREATE TABLE 같은 DDL 문을 자동으로 생성해주는 기능도 있다. 이런 기능들을 사용하면 데이터베이스 설계 중심의 패러다임을 객체 설계 중심으로 역전시킬 수 있다.

 

유지보수

SQL에 의존적인 개발에서도 이야기했듯이 SQL을 직접 다루면 엔티티에 필드를 하나만 추가해도 관련된 등록, 수정, 조회 SQL과 결과를 매핑하기 위한 JDBC API 코드를 모두 변경해야 했다. 반면에 JPA를 사용하면 이런 과정을 JPA가 대신 처리해주므로 필드를 추가하거나 삭제해도 수정해야 할 코드가 줄어든다. 따라서 개발자가 작성해야 했던 SQL과 JDBC API 코드를 JPA가 대신 처리해주므로 유지보수해야 하는 코드 수가 줄어든다. 또한 JPA가 패러다임의 불일치 문제를 해결해주므로 객체지향 언어가 가진 장점들을 활용해서 유연하고 유지보수하기 좋은 도메인 모델을 편리하게 설계할 수 있다.

 

패러다임의 불일치 해결

지금까지 패러다임의 불일치 문제가 얼마나 심각한지 다루었고, JPA를 통한 해결책도 간단히 보았다. JPA는 상속, 연관관계, 객체 그래프 탐색, 비교하기와 같은 패러다임의 불일치 문제를 해결해준다. 

 

성능

JPA는 애플리케이션과 데이터베이스 사이에서 다양한 성능 최적화 기회를 제공한다. JPA는 애플리케이션과 데이터베이스 사이에서 동작한다. 이렇게 애플리케이션과 데이터베이스 사이에 계층이 하나 더 있으면 최적화 관점에서 시도해 볼 수 있는 것들이 많다. 같은 트랜잭션 안에서 같은 회원을 두 번 조회하는 코드의 경우 JDBC API를 사용해서 해당 코드를 직접 작성했다면 회원을 조회할 때마다 SELEECT SQL을 사용해서 데이터베이스와 두 번 통신했을 것이다. JPA를 사용하면서 회원을 조회하는 SELECT SQL을 한 번만 데이터베이스에 전달하고 두 번째는 조회한 회원 객체를 재사용한다. (참고로 하이버네이트는 SQL 힌트를 넣을 수 있는 기능도 제공한다)

 

데이터 접근 추상화와 벤더 독립성 

관계형 데이터베이스는 같은 기능도 벤더마다 사용법이 다른 경우가 많다. 단적인 예로 페이징 처리는 데이터베이스마다 달라서 사용법을 각각 배워야 한다. 결국, 애플리케이션은 처음 선택한 데이터베이스 기술에 종속되고 다른 데이터베이스로 변경하기는 매우 어렵다. 

 

표준

JPA는 자바 진영의 ORM 기술 표준이다. 앞서 이야기했듰이 표준을 사용하면 다른 구현 기술로 손쉽게 변경할 수 있다. 

 

 

 

728x90

'프로그래밍 공부 > JPA' 카테고리의 다른 글

Querydsl - 기본문법  (0) 2022.07.21
3. 영속성 관리  (0) 2020.03.14
2. JPA 시작  (0) 2020.03.11