JPA 기초 1 - ORM(Object Relational Mapping)

JPA 기초 1 - ORM(Object Relational Mapping)

ORM을 사용해야만 하는 이유

 

📕 ORM(Object Relational Mapping)


ORM이란 것은 RDBMS 인스턴스와 쉽게 상호작용해 쿼리작성의 부담을 줄이기 위한 목적의 프로그래밍 방식이다.

그리고, 많이들 들어보았을 JPA는 자바진영의 ORM 표준 인터페이스이다.

또한, 현 시점 가장 많이 사용되는 JPA 구현체는 하이버네이트(Hibernate)이다.

이 기술들의 핵심 컨셉은 애플리케이션데이터베이스 사이에 가상의 데이터베이스(영속성 컨텍스트)라는 인디렉션(간접 참조계층)을 만드는 것이다.


Mybatis등의 다른 데이터 접근 기술을 사용하다 JPA를 배우는 개발자가 착각할 수 있는것은 반드시 JPA를 사용해야만 객체지향적인 코드를 작성할 수 있느냐는 것이다.

이는 필자가 생각하기에 약간 잘못된 접근 방법이라고 생각하는데, 객체지향적으로 코드를 작성한다면 저장소가 파일시스템이든, RDBMS든, NoSQL이든 관계가 없어지기 때문에 JPA는 객체지향과는 큰 관계가 없다.

오히려 필자는 JPA와 도메인 객체를 결합하게되면 도메인이 RDBMS에 오염된다고 생각하기 때문에 객체지향적으로 안티패턴 이라고까지 생각한다.


그럼에도 불구하고 ORM, 그중 특히 하이버네이트를 사용하는 이유는 충분하다.


  • LGPL 메이저 오픈 소스
    • 상용으로 사용하더라도 코드를 공개하지 않아도 괜찮으며, 전 세계의 뛰어난 오픈 소스 개발자들이 두 눈에 불을 켜고 유지보수에 매달리고 있다.
  • 좋은 성능
    • 하이버네이트는 내부적으로 캐시를 사용하기 때문에 성능이 좋다. 내부적으로 1차캐시와 2차캐시가 있는데, 1차캐시는 기본적으로 활성화돼있다.
  • 직접 작성할 필요 없으며, 데이터베이스에 독립적인 SQL
    • HQL(Hibernate Query Language)은 객체 지향 버전의 SQL로, 하이버네이트는 데이터베이스에 독립적인 쿼리를 만들어낸다. 심지어 이러한 쿼리를 개발자가 하나하나 직접 하드코딩하는 것이 아닌, 자바 코드 몇자면 자동으로 생성이 된다. 따라서 하이버네이트를 사용한다면 쿼리를 작성하는데 소요되는 시간이 0에 가깝게 줄어들며, 특정 데이터베이스에 종속적인 쿼리를 작성할 필요도 없어진다. 즉, 혹여나 프로젝트 중간에 데이터베이스가 변경되더라도 대규모의 쿼리수정을 할 필요가 없게 된다. 단, 이렇게 데이터베이스에 독립적인 애플리케이션을 개발하기 위해서는 하이버네이트에서 제공하는 네이티브 쿼리를 사용하지 않아야만 한다.
  • 테이블 자동 생성 (ddl-auto 옵션)
    • 하이버네이트는 자동으로 테이블을 생성해준다. 개발 초기에 데이터베이스 테이블을 하나하나 직접 생성하지 않아도 되기 때문에 빠르게 개발을 시작할 수 있게 도와준다.
  • 조인 단순화
    • 여러 테이블의 데이터를 함께 가져오는 조인 작업이 하이버네이트에서는 연관관계 매핑이라는 이름으로 지원이 되며, 이 매핑을 잘 해두면 조인작업이 매우 쉽게 처리된다.
  • 데이터베이스 상태, 통계 제공
    • 하이버네이트는 쿼리와 데이터베이스의 상태에 대한 통계정보를 제공해준다. 따라서 개발 도중 쿼리의 성능을 간접적으로 계속해서 확인할 수 있다.


필자가 JPA로 실무를 보며 느꼈던 중요한 부분들은 다음과 같다.

  • 사용하지 않을 수 있다면, 네이티브 쿼리는 최후의 최후까지 사용하지 않아야 한다.
  • 중요한 처리를 JPA의 연관관계 매핑을 통해 처리하려 들 경우 N+1, 동일성 불일치 등의 골치아픈 side-effect가 발생한다.
  • 항상 트랜잭션과 영속성 컨텍스트를 머릿속에 그리고 있어야만 한다.
  • JPA Entity는 단순히 RDBMS의 테이블 구조를 따라갈 뿐이다.
  • 도메인 모델(DM)과 영속성 모델(PM)을 분리하자.
  • 데이터 중심적인 사고에 빠지지않고, 항상 객체지향적으로 생각하고 SOLID 원칙을 준수할 수 있도록 노력해야만 한다.


약어개념
SRP단일 책임 원칙 (Single responsibility principle)
한 클래스는 하나의 책임만 가져야 한다.
OCP개방-폐쇄 원칙 (Open/closed principle)
“소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.”
LSP리스코프 치환 원칙 (Liskov substitution principle)
“프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.” 계약에 의한 설계를 참고하라.
ISP인터페이스 분리 원칙 (Interface segregation principle)
“특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.”
DIP의존관계 역전 원칙 (Dependency inversion principle)
프로그래머는 “추상화에 의존해야지, 구체화에 의존하면 안된다.” 의존성 주입은 이 원칙을 따르는 방법 중 하나다.



© 2022. All rights reserved.