본문 바로가기
Spring/JPA

[JPA] JPA 등장 배경 + ORM에 대한 이야기

by 코딩균 2021. 9. 10.
JPA 등장 배경

 

JDBC API로 언제까지 SQL문 짜고 업데이트 사항 발생하면 하나씩 DAO에 가서 수정할래?

 

JAVA에서는 JDBC API를 이용하여 Web Application에서 DB로 부터 data를 추출해서 가져와야 했다. 직접 SQL을 작성한 후 JDBC API를 이용하여 SQL문을 전달하는 방식이다.

아래는 JDBC template을 활용하여 상품 DB와 상품 Service 코드 사이에서 DB를 가져오고 매핑해주는 DAO 계층이 담긴 class의 메서드 중 하나이다.

public List<TodayClass> getProductHomeTodayClass(){
        String query = "SELECT OnlineClass.idx, thumbnail, title FROM OnlineClass\n" +
                "WHERE status=\"ACTIVE\" and DATE_FORMAT(createdAt, \"%Y-%m-%d\") = CURDATE()\n" +
                "LIMIT 6";

        List<TodayClass> result = this.jdbcTemplate.query(query,
                (rs,rsNum)-> new TodayClass(
                        rs.getInt("idx"),
                        rs.getString("thumbnail"),
                        rs.getString("title")
                )
                );
        System.out.println("[DAO] getProductHomeTodayClass complete");
        return result;

    }

 

여러가지 불편한 점을 확인할 수 있다

  • 조회 결과가 객체가 아닌 Data base의 결과물이므로 직접 객체로 매핑해주어야 한다. 
  • 객체를 DB에 CRUD 하기 위해서는 많은 SQL문과 JDBC API 관련 코드를 작성해야 한다.
  • SQL에 너무 많은 의존을 하게 되어 객체 지향적인 Web Application 설계가 쉽지 않다.

예를 들어 상품 (Product)에 대한 생성 일자(createdAt)를 추가로 조회해야한다고 가정하자.

먼저 위의 코드에서 query 변수에 담긴 SQL문을 수정해야하고

매핑 코드에서 DB 결과인 생성 일자와 TodayClass의 생성일자를 매핑해주는 코드까지 작성해야 한다. 

이에 따라 Web Application 단계에서 Product라는 모델을 생성해도 결국에 DB가 잘 조회되는지, 생성하는지, UpdAte되는지 확인하기 위해서는 DAO 레벨까지 사라펴봐야 한다는 것이다. 

  • 개발에서의 계층 분할이 어렵다.
  • 엔티티 (Model)을 신뢰하기 어렵다.
  • 객체지향적으로 프로그래밍 하기 어렵다.
객체 지향 프로그래밍이 제공하는 복잡성 제어 장치 : 추상화, 캡슐화, 정보은닉, 상속, 다형성

RDBS와 객체 패러다임 불일치 문제

두개의 목적이 다르기 대문에 기능과 표현방법이 다르다. 데이터의 저장 구조가 다르기 때문에 객체를 DB에 그래도 저장하는 것은 한계가 있다. (그래서 JDBC API로 DB row 데이터를 불러와서 객체와 Mapping 시켜준는거 아닌가 싶다)

에플리케이션은 JAVA로 개발하고 데이터는 DB저장해야 한다면 위의 DAO 같은 계층들로 인해 중간에서 중재하는 코드를 굉장히 많이 작성해야 한다.

 

  • SQL에 묶여 있으면 data를 탐색 할 수 있는 제약이 크다

DB table 연관 관계에 따른 자유로운 탐색 제약

SELECT userName, phoneNumber FROM User

SQL로 데이터를 가져오면 선택된 Data, Join한 테이블의 data만 가져올 수 있다.

따라서 객체 지향적으로 생각해서 자유롭게 다른 연관된 테이블(객체)로 이동하는 것에 제약이 있다.

(이미 SELECT로 가져올거 가져왔잖아)

비즈니스 로직에 따라 사용하는 테이블과 객체가 다른데, 객체간의 연관성이 언제 사라질지도 모르기 때문이다. 결국 다시 DAO로 가서 SQL문을 어떤 것을 날렸는지 확인해야 한다. 어디까지 내가 data를 가져올 수 있을지 확인하려면 말이다.

=> SQL에 Entity가 논리적으로 종속되었다

 

 

JPA (Java Persistence API) 

자바의 자바 ORM 기술에 대한 API 표준 명세서

 

Application <-> JPA <-> JDBC API <-> DB

 

JPA는 JDBC API를 활용해서 객체와 DB 테이블을 매핑해준다. JPA에서 제공해주는 메서드를 통해서 객체를 DB에 CRUD 할 수 있다. 

jpa.persist(user);

이런식으로 영속성 컨텍스트 (Persistence Context) 안에서 Persist를 통해서 객체의 Data를 DB에 저장하게 된다.

JPA의 역할의 다음과 같이 정리 가능하다

 

  • SQL 생성
  • JDBC API 사용하여 DB에서 data 가져오기
  • 객체와 DB data 매핑

=> 객체와 DB의 패러다임 불일치 해결

 

 

ORM (Object-Relational Mapping)

객체와 데이터베이스를 매핑하여 데이터를 객체지향적으로 관리할 수 있도록 도와주는 기술

자바에서는 Hibernate ORM 프레임 워크가 객체와 DB 데이터의 패러다임 불일치 문제를 대부분 해결해준다

ORM을 기반으로 JPA는 구성되며 ORM을 활용할 수 있도록 API화 하는 것이 JPA다.

 

 

JPA 사용해야 하는 이유?
  • SQL문을 직접 작성하지 않아도 된다 -> 객체 지향적인 설계 가능
  • 유지 보수가 쉽다 <- 매핑을 JPA가 관리해주기 때문에 수정시, 직접 JDBC API단까지 내려가지 않아도 된다
  • 패러다임 불일치 해결
  • 성능이 뛰어나다 <- JDBC API를 이용했을 시에는 여러번 쿼리 날려야 할 것을 한번으로 축소 가능하고, 엔티티를 재사용 가능하다 (추후 영속성 컨텍스트에서 포스팅)
  • 데이터베이스 종류에 제한받지 않는다 <- Dialect으로 각자 다른 데이터베이스의 언어들이 추상화되어있다. (추후 세팅에서 dialect에 대해 포스팅)

 

번외

통계쿼리 같은 복잡한 SQL은 JPA에서 처리하는 것보다는 마이바티스, JdbcTemplate이나 JPA의 네이티브 SQL을 사용하는 것이 좋다. JPA는 실시간 처리용 쿼리 보내는 데에 최적화 되었다.

 

 

자바 ORM 표준 JPA 프로그래밍 (저자 : 김영한님)의 책을 공부하고 활용하여 적은 개인 공부 정리 포스팅입니다