본문 바로가기

프로그래밍(TA, AA)/개발방법론

[JPA] 왜 ORM을 사용해야 하는가?

하이버네이트를 마스터하고 싶다면, 하이버네이트가 제공하는 플러시, 페치, 캐시 기능의 다양한 옵션과 동작 원리를 깊이 있게 공부해야 한다. 이러한 것을 마스터해야 하이버네이트를 사용한 대화형 요청 처리를 구현하거나 성능 최적화를 할 수 있게 될 것이다.

 

하이버네이트 사용하기 이전의 목표.

  • 하이버네이트를 사용해서 도메인 클래스가 하나인 간단한 CRUD 애플리케이션을 만들겠다
  • 일대다 관계에 있는 도메인 클래스 두 개를 매핑하고 두 도메인 클래스에 대한 CRUD 애플리케이션을 만들겠다.
  • 다형성을 지원하는 계층 구조의 도메인 클래스를 만든 뒤 그것에 대한 CRUD 애플리케이션을 만들겠다.

관계형데이터베이스가 ORM의 일부를 차지하고 있다면 당연히 다른 한 쪽은 자바 애플리케이션에서 SQL을 사용해 데이터베이스로 영속화하거나 데이터베이스에서 불러오는 객체로 구성돼 있다.

 

객체지향 애플리케이션에서는 영속화를 통해 객체가 자신을 만들어 낸 프로세스를 벗어나서도 존재할 수 있다. 객체의 상태는 디스크에 저장될 수 있으며, 추후 필요할때 같은 상태를 갖는 객체로 다시 생성될 수 있다. 그것은 상호 연고나된 객체망 모두 영속적인 상태(persistent)가 될 수 있고 추후 새로운 프로세스에서 다시 만들어질 수 있다는 뜻이다. 대부분의 객체는 영속적인 상태가 아닌데, 비영속(transient) 객체는 자신을 생성한 프로세스의 생명주기에 국한된 제한적인 수명을 갖는다. 거의 대부분의 자바 애플리케이션에는 영속(persistent) 객체와 비영속(transient) 객체가 혼재돼 있어 영속적인 데이터를 관리해줄 서브시스템이 필요하다.

 

영속화에 관한 논의에서는 다음과 같은 상황을 고려하는 것이 좋다.

  • 구조적인 데이터의 저장, 구성, 조회
  • 동시성과 데이터 무결성
  • 데이터 공유

도메인 모델을 사용하는 애플리케이션은 직접적으로 비즈니스 엔티티에 대해 테이블 형태의 표현을 직접 사용하지 않고, 비즈니스 엔티티를 객체지향적으로 표현한 자체적인 모델을 갖고 있다. 예를 들어 데이터베이스에 ITEM과 BID라는 테이블이 있다면 자바 애플리케이션에는 Item과 Bid라는 클래스를 정의하는 식이다.

 

그리고 SQL 결과 집합의 행(row)와 열(column)을 직접 이용하는 대신, 비즈니스 로직은 이러한 객체지향 도메인 모델과 그것을 실행시간에 realization한 상호 연관된 객체망과 상호작용한다. Bid에 대한 각 인스턴스는 경매 Item을 참조하며, 각 Item은 여러 Bid 인스턴스에 대한 참조를 컬렉션으로 가지고 있을 것이다. 비즈니스 로직은 DB에서 실행되지 않고, 애플리케이션 단에 구현돼 있다. 

 

비즈니스 로직을 다루는 애플리케이션에서 도메인 모델을 사용하는 접근법은 코드의 재사용성과 유지보수성을 향상시켜준다. 대부분의 애플리케이션은 상당히 많은 양의 데이터를 수정하고 처리하는 프로시저를 실행할 필요가 있다. 한편으로 애플리케이션 모듈은 일반적인 온라인 트랜잭션 처리 로직을 애플리케이션 단에서 처리하는 객체지향 도메인 모델의 혜택을 얻을 수 있다. 따라서 영속적인 데이터를 애플리케이션 코드로 가져오는 효율적인 방법이 필요하다. 

 

자바 애플리케이션에서 30%에 달하는 소스 코드가 지루한 SQL/JDBC를 다루고 손수 객체/관계형 패러다임 불일치를 처리하는데 쓰인다. 결국 프로젝트의 데이터베이스 추상화 계층이 복잡해지고 유연함을 갖추지 못해서 거의 실패직전에 다다르기도 한다.

 

모델링은 가장 비용이 많이 드는 분야 중 하나이다. 관계형 모델이나 도메인 모델은 둘 모두 동일한 비즈니스 엔티티를 대상으로 하지만 순수 객체지향주의자는 경험이 많은 관계형 데이터모델러와는 다른 방법으로 비즈니스 엔티티를 모델링하게 된다. 이 문제에 대한 일반적인 해결책은 도메인 모델과 구현한 클래스를 변형해 가면서 SQL 데이터베이스 스키마에 맞추는 것이다.

 

관계형 모델링과 객체지향 두 패러다임 사이의 차이를 어떻게 이을지 설명해주는 수식 같은 것을 기대하긴 어렵고, 현재로서는 둘 사이를 이어줄 어떠한 우아한 방법도 없다. 더 많은 비용을 들게 하는 생산성의 악화와 유연성 없는 시스템이 만들어지는 것이 도메인 모델링의 불일치 때문만은 아니다. 더 중요한 원인은 JDBC API 자체에 있다. JDBC나 SQL은 SQL 데이터베이스에서 데이터를 옮길때 문장 중심, 즉 명령중심적인 접근법을 사용한다. 조회를 하거나 데이터를 다룰때 그와 관련된 테이블이나 열은 최소한 세 번(insert, update, select)은 기술해야 하고, 이것은 설계와 구현에 그만큼 시간이 늘어난다는 것을 의미한다.

 

대규모 애플리케이션에서는 관심사에 따라 클래스를 구성하는 것이 일반적이다. "persistent / presentation / workflow / business logic"과 같은 관심사가 있다. 전형적인 객체지향 아키텍처에서는 위와 같은 관심사를 나타내는 코드 계층을 포함한다. 이처럼 계층화된 시스템 구조에서 영속화를 담당하는 모든 클래스와 컴포넌트를 묶어 영속화 계층으로 나누는 것은 평범하면서도 확실히 좋은 방법이다. 

  • 영속화 계층: 영속화 계층은 하나 또는 여러 개의 데이터 저장소로부터 데이터를 가져오거나 데이터 저장소로 데이터를 저장하는 일을 담당하는 클래스나 컴포넌트의 그룹이다. 이 계층은 반드시 비즈니스 도메인엔티티(메타데이터 모델 등)을 포함한다.

 

SQL과 JDBC를 이용해서 직접 작성한 영속화 계층

자바 영속화에 접근하는 가장 흔한 방법은 애플리케이션 프로그래머들이 직접 SQL과 JDBC를 다루는 것이다. 개발자들은 SQL을 이해하고, 더 나아가 DAO(data access object) 패턴을 사용하여 복잡한 JDBC 코드와 이식이 불가능한 SQL을 비즈니스 로직으로부터 감추는 방법을 사용할 수 있다.

 

DAO 패턴은 훌륭한 패턴이다. 그래서 ORM을 쓰더라도 DAO패턴을 쓰는 것을 종종 권장하기도 한다. 하지만 도메인 클래스에 대한 영속화 과정을 직접 코딩한다는 것은 상당히 고된 일이다. 특히 여러 벤더를 지원하는 SQL을 작성해야 할 때는 더욱 그렇다. 결국 해당 작업은 개발 공수 중 상당 부분을 차지하게 된다. 더 나아가 요구사항이 바뀌면 직접 작성한 솔루션은 더 많은 주의와 유지보수 노력이 필요하다. 모든 ORM 소프트웨어는 생산성을 떨어뜨리는 지루하고 반복적인 공통 사항을 처리해줄 것이다.

 

영속화의 여러 대안 기법이 존재하지만 최선의 선택은 하이버네이트를 통해 이용하고 있는 ORM이다. 개발자들은 ORM이라는 용어를 다양한 의미로 사용한다. 어떤 사람들은 객체 관계형 매핑(object relational mapping)으로 부르기도 하고, 또 어떤 사람들은 간단한 객체 매핑(object mapping)이라는 표현을 선호하기도 한다. 객체와 관계형 사이의 두 패러다임 간 발생하는 불일치 문제를 강조한 것이다.

 


ORM이란 무엇인가?

객체/관계형 매핑은 객체와 데이터베이스 사이의 매핑을 정의한 메타데이터를 이용하여 자바 애플리케이션 내의 객체를 관계형 데이터베이스의 테이블로 자동으로(그리고 투명하게) 영속화하는 것이다.

 

본질적으로, ORM은 데이터를 어떤 표현방식에서 다른 표현방식 (그리도 그 반대로도) 변환함으로써 동작한다. 이 때문에 약간의 성능 저하가 야기도리지도 모른다. 하지만 ORM을 미들웨어로 구현한다면 직접 영속화 계층을 코딩할 때는 얻기 힘든 최적화를 할 기회가 많이 생긴다. 변환 작업에 필요한 메타데이터를 만들고 관리하는 것이 개발 기간에 부담이 될 수도 있지만 직접 만든 솔루션 유지보수에 필요한 비용보다는 적을 것이다.

 

ORM 솔루션은 아래의 네 부분으로 구성돼 있다.

  • 영속 클래스 객체에 대한 기본적인 CRUD를 수행하는 API
  • 클래스 자체와 해당 클래스의 프로퍼티를 참조하는 쿼리를 작성할 수 있는 언어나 API
  • 매핑 메타데이터 작성을 위한 기반 시설
  • ORM 구현이 트랜잭션을 적용한 객체와 상호작용하여 변경감지(dirty checking), 지연 연관 관계 페치(lazy association fetching) 등의 최적화를 수행하도록 돕는 기법

여기서는 ORM이 메타데이터 기반의 설정으로부터 SQL이 자동으로 생성되는 모든 영속화 계층을 포함할때 완전한(full) ORM이라는 용어를 쓴다. 객체/관계형 매핑 문제를 개발자들이 직접 JDBC로 SQL을 하드코딩해서 해결하는 영속화 계층은 완전한 ORM에 해당하지 않는다. ORM을 사용하면 애플리케이션은 ORM API와 도메인 모델 클래스와 상호작용하며, 기반하는 SQL/JDBC로부터 추상화한 형태가 된다. ORM 엔진은 그것의 특징이나 구현 방법에 따라 낙관적 잠금과 캐싱 같은 사안을 책임지기도 하여 애플리케이션을 이러한 관심사로 부터 해방시켜 준다.

 

다음은 ORM을 구현하는 다양한 방법이다. ORM의 품질은 아래의 네단계로 정의할 수 있다.

  • 순수 관계형
    사용자 인터페이스를 포함한 전체 애플리케이션이 관계형 모델과 SQL 기반의 관계형 연산으로 구성돼 있다. 이 접근법은 대규모 시스템에는 부적합하지만 코드 재사용 수준이 낮아도 크게 상관없는 작은 규모의 애플리케이션에는 탁월한 해결책이 될 수 있다. 직접적인 SQL은 모든 측면에서 세밀하게 조정할 수 있지만, 이식성이나 유지보수성이 떨어진다는 단점이 있고, 특히 장기적으로는 더욱 그러하다. 이런 부류에 속하는 애플리케이션은 종종 저장 프로시저를 과도하게 써서 비즈니스 계층에서 해야할 일을 데이커베이스로 옮겨 놓기도 한다.
  • 가벼운 객체 매핑
    엔티티를 클래스로 표현하고 이 클래스를 직접 관계형 테이블로 매핑한다. 손수 작성한 SQL/JDBC 코드는 잘 알려진 디자인 패턴을 활용하여 비즈니스 계층으로부터 분리하여 감춰진다. 이 접근법은 굉장히 널리 퍼져 있으며 엔티티 개수가 적거나 애플리케이션에 일반화된, 메타데이터 기반의 데이터 모델이 있을때 알맞은 접근버이다. 이런 종류의 애플리케이션에도 저장 프로시저가 있을 수 있다.
  • 중간 정도의 객체 매핑
    애플리케이션을 객체 모델 중심으로 설계한다. SQL은 빌드시에 코드 생성 도구를 이용해 생성되거나, 프레임워크 코드에 의해 실행 시에 생성된다. 객체 간의 연관 관계는 영속화 메커니즘이 지원하며, 쿼리를 객체지향적인 표현 언어를 사용하여 기술할 수 있다. 객체가 영속화 계층에 의해 캐싱된다. 여러 훌륭한 ORM 제품과 직접 만든 영속화 계층이라면 최소한 이 정도 수준의 기능을 제공한다. 이 접근법은 트랜잭션이 복잡하고, 특히 여러 데이터베이스 간의 이식성이 중요한 중소규모의 애플리케이셔에 적합하다. 이런 애플리케이션은 보통 저장 프로시저를 사용하지 않는다.
  • 완전한 객체 매핑
    완전한 객체 매핑은 복잡한 객체 모델링을 지원한다. composition, inheritance, polymorphism, persistence by reachability를 지원한다. 이러한 영속화 계층은 투명한 영속화(transparent persistence)라는 특징이 있다. 이는 영속 클래스가 어떤 특정 기본 클래스를 상속하거나 특정 인터페이스를 구현하지 않아도 된다는 뜻이다. 또한 효율적인 fetch 전략(lazy, eager, prefetching)과 캐싱 전략이 애플리케이션에 투명하게 구현돼 있다. 이 정도 수준의 기능은 손수 개발한 영속화 계층으로는 달성하기가 상당히 힘들다. 많은 상용 도구와 오픈소스 자바 ORM 도구가 이런 수준의 품질을 달성한 바 있다.

완전한 객체 매핑 수준이 하이버네이트 ORM의 정의다. 아래는 일반적인 ORM 문제를 나타낸 목록이다.

  1. 영속 클래스는 어떻게 생겼는가? 영속화 도구는 얼마나 투명하게 동작하는가? 비즈니스 도메인을 나타내는 클래스에 특정한 프로그래밍 모델이나 규약을 채택해야 하는가?
  2. 매핑 메타데이터를 어떤 형태로 정의할 것인가? 객체/관계형 사이의 변형은 전적으로 메타데이터에 의해 이루어진다. 따라서 메타데이터의 형식과 정의가 중요하다. 그렇다면 ORM 도구는 메타데이터를 그래픽 화면을 통해 조작할 수 있게 GUI 인터페이스를 제공해야 하는가? 아니면 메타데이터를 정의하는 또 다른 좋은 접근법은 없을까?
  3. 어떤 방법으로 객체 동일성(identity)이나 동등(equality)을 그와 연관된 데이터베이스(primary key) 식별자와 연관지을 것이가? 어떻게 특정 클래스의 객체를 특정 테이블의 행으로 매핑할 것인가?
  4. 클래스 상속 계층 구조를 어떻게 매핑할 것인가? 이 문제엔 몇가지 표준 전략이 있다. 다형적인 연관 관계, 추상 클래스, 인터페이스는 어떻게 할 것인가?
  5. 영속화 로직이 실행 시에 비즈니스 도메인 객체와 어떻게 상호작용 하는가? 이문제는 제네릭 프로그래밍과 관련이 있는 문제로, 소스 생성, 런타임 리플렉션, 런타임 바이트 코드 생성, 빌드타임 바이트코드 조작을 비롯한 여러 해결 방안이 있다. 이 문제에 대한 해결 방안은 빌드 과정에 영향을 줄지도 모른다.
  6. 영속 객체의 생명주기란 무엇인가? 어떤 객체의 생명주기가 연관 관계에 있는 다른 객체의 생명주기에 의존적인가? 객체의 생명주기를 데이터베이스 행의 생명주기로 어떻게 해석할 것인가?
  7. 정렬, 검색, 집계 연산과 관련하여 어떤 기능이 제공되는가? 애플리케이션은 이러한 것들을 메모리에서 처리할 수도 있지만 관계형 기술을 효율적으로 사용하려면 이러한 작업을 데이터베이스에서 수행해야 할 때가 있다.
  8. 연관 관계에 있는 데이터를 어떻게 효율적으로 가져올 것인가? 관계형 데이터에 효율적으로 접근하는 방법은 보통 테이블 조인을 사용하는 것이다. 객체지향 애플리케이션은 보통 객체망을 통해 데이터에 접근한다. 이 두 가지 데이터 접근 방법을 사용할 때는 n+1 조회 문제와 카테시안 곱 문제를 조심해야 한다.

 

왜 ORM인가?

소위 말하는 ORM의 이점은 성가신 SQL로부터 개발자를 보호해 준다는 것이다. 이러한 관점은 객체지향 개발자가 SQL이나 관계형 데이터베이스를 잘 이해하지 않아도 되고, 개발자들이 SQL을 어떻게든 불쾌하게 여긴다고 간주한다. 하지만 이와는 반대로 ORM을 사용하려면 자바개발자도 반드시 관계형 모델링과 SQL에 충분히 익숙해야 한다. ORM은 그런 힘든 방법을 이미 경험해본 개발자들이 사용하게끔 만든 고급 기법에 속한다. 하이버네이트를 효율적으로 사용하려면 SQL을 보고 해당 문장이 야기할 수 있는 문제와 잠재적인 성능을 이해할 수 있어야 한다. 다음은 ORM과 하이버네이트가 주는 혜택이다.

 

생산성

영속화와 관련된 코드는 아마도 자바 애플리케이션에서 가장 지루한 코드일 수 있다. 하이버네이트는 그다지 썩 내키지 않는 작업을 없애주고 비즈니스 문제에 집중할 수 있게 해준다. 도메인 모델로부터 시작하는 하향식이든 기존의 데이터베이스 스키마로부터 시작하는 상향식이든, 어떤 애플리케이션 개발 전략을 선호하든 간에 하이버네이트와 적절한 도구를 함께 활용하면 개발에 소요되는 시간을 크게 줄일 수 있다.

 

유지보수성

적은 코드 줄수(LOC, line of code)를 유지할수록 시스템을 쉽게 이해할 수 있다. 왜냐하면 반복적인 코드보다 비즈니스 로직이 좀 더 명확히 드러나기 때문이다. 더 중요한 점은 코드 줄 수가 적을수록 시스템을 리팩토링하기가 더 쉽다는 것이다. 자동화된 객체/관계형 영속화는 LOC를 상당히 줄여준다. 물론 코드의 줄 수로 애플리케이션의 복잡도를 측정하는 것은 논란의 여지가 있다.

하지만 하이버네트가 유지보수하기 좋은 다른 이유도 있다. 직접 작성한 영속화 시스템에서는 관계형 표현과 도메인을 구현한 객체 모델 사이에 필연적으로 긴장감이 존재한다. 즉, 어떤 것을 변경하면 다른 쪽도 항상 바꿔야 하기 때문에 한쪽의 표현법을 설계할 때 다른 쪽의 존재를 수용하기 위한 타협점을 내포하고 있어야 한다. ORM은 이 두 모델 사이의 완충지대를 제공하여 자바 쪽에서 더욱 우아한 객체지향을 가능케 하고 각 모델은 상대방의 자잘한 변경사항으로 인해 바뀌지 않아도 된다.

 

성능

영속화 작업에는 여러가지 최적화가 가능하다. 어떤 최적화 방법은 SQL/JDBC를 사용하여 직접 작성하는 편이 훨씬 더 쉽다. 하지만 대부분의 최적화는 자동화된 ORM을 쓰는 것이 훨씬 쉽다. 시간적인 제약이 있는 프로젝트에서는 손수 작성한 영속화 솔루션을 써서 몇가지 최적화를 꾀할 수 있다. 하지만 하이버네이트는 항상 그보다 많은 최적화를 가능하게 해준다. 게다가 자동화된 영속화 솔루션은 개발자의 생산성을 높여주기 때문에 얼마 남지 않은 병목 현상을 처리하는 데 더 많은 시간을 투자할 수 있다.

 

벤더독립성

ORM은 기반 SQL 데이터베이스나 SQL dialect로부터 애플리케이션을 추상화한다. ORM이 다양한 데이터베이스를 지원한다면 이는 애플리케이션이 일정 수준의 이식성을 확보할 수 있다는 뜻이다. 데이터베이스의 능력과 성능은 각기 다르며, 완벽한 이식성을 보장하려면 더욱 강력한 플랫폼의 장점을 희생해야하는 측면도 존재하기는 한다. 그럼에도 불구하고 ORM을 이용하면 플랫폼 이식성을 갖춘 애플리케이션을 개발하기가 훨씬 쉽다. 심지어 플랫폼 이식성이 필요없다고 하더라도 ORM은 벤더에 종속되어 발생할 수 있는 위험 요소를 제거해준다.

 

게다가 데이터베이스 독립성은 개발 시에 개발자들이 로컬에서 가벼운 데이터를 사용하고 실제 환경에서는 다른 데이터베이스로 배포하는 것을 가능케 한다. 

 

하이버네이트, JPA

하이버네이트는 완전한 객체/관계형 매핑 도구로서 앞서 나열한 ORM이 가져다 주는 이점을 모두 제공한다. 하이버네이트에서는 하이버네이트 개발자가 설꼐한 고유 API를 쓴다. 쿼리 인터페이스와 쿼리 언어, 객체/관계형 매핑 메타데이터를 정의하는 방법도 마찬가지다.

 

처음으로 하이버네이트를 사용하는 프로젝트를 시작하기에 앞서 하위 명세에 해당하는 자바 퍼시스턴스도 고려해봐야 한다. 성공적인 데이터 영속화 솔루션으로서 하이버네이트는 새로운 표준의 영속화 부문에서 중요한 역할을 수행하고 있다.

 

하이버네이트는 자바 퍼시스턴스를 구현하며, JAP 엔진은 동적으로 교체가 가능하기 때문에 새롭고 흥미로운 소프트웨어 조합이 가능하다. 사용자는 다양한 하이버네이트 소프트웨어 모듈을 선택할 수 있고 그것들을 프로젝트에서 쓰는 기술과 비즈니스 요구사항에 맞게 조합할 수 있다.

 

하이버네이트 코어

하이버네이트 코어는 하이버네이트로 알려져 있다. 하이버네이트 코어는 고유 API와 XML 파일에 저장되는 매핑 메타데이터와 함께 기본 영속화 서비스에 해당한다. 그리고 HQL(SQL과 거의 비슷)이라는 쿼리 언어를 비롯해서 프로그램 방식의 쿼리 인터페이스인 Criteria와 Example 쿼리를 포함하고 있다. 하이버네이트 코어는 다른 모든 모듈이 구축되는 실질적인 기반이자 플랫폼으로서 모든 부문에 걸쳐 수백 가지에 이르는 옵션과 기능을 제공해 준다.

하이버네이트 코어는 다른 프레임워크 또는 특정한 모든 JDK 실행 환경과는 별개로 독립적으로 사용할 수 있다. 하이버네이트 코어는 모든 자바 애플리케이션 서버, 스윙 애플리케이션, 간단한 서블릿 컨테이너 등에서 사용할 수 있다. 하이버네이트에서 쓸 데이터소스를 설정할 수만 있다면 바로 쓸 수 있다. (영속화 계층에 있는) 애플리케이션 코드는 하이버네이트 API와 쿼리를 사용할 것이며, 매핑 메타데이터는 하이버네이트 고유의 XML vkdlffh wkrtjdehlf rjtdlek.

 

하이버네이트 EntityManager

JPA 명세에는 프로그래밍 인터페이스, 영속 객체에 대한 생명주기 규칙, 쿼리 기능도 정의돼 있다. JPA의 이 부분에 대한 하이버네이트 구현으로 하이버네이트 EntityManager가 있다. 이것은 하이버네이트 코어 위에 올려 놓을 수 있는 또 다른 부가적인 모듈이다. 필요하다면 일반 하이버네이트 인터페이스를 사용하거나 JDBC Connection을 사용할 수도 있다. 하이버네이트의 기본 기능은 모든 면에서 JPA 영속화 기능을 포함한다. (EntityManager는 JPA 호환성을 제공하는 하이버네이트 코어를 감싸는 작은 구현체다)

 

표준화된 인터페이스와 쿼리 언어를 사용하면 JPA와 호환 가능한 영속화 계층을 모든 애플리케이션 서버에서 사용할 수 있다는 장점이 있다. 또는 JPA를 표준화된 특정 런타임 환경이 아닌 일반 자바에서도 사용할 수 있다.

 

하이버네이트 애노테이션을 하이버네이트의 EntityManager와 함께 사용하는 것을 고려해봐야 한다. 애플리케이션 코드를 JPA 인터페이스와 JPA 쿼리로 작성하면서도 매핑 대부분에 JPA 어노테이션을 쓰지 않는 것은 통례가 아니다.

 

하이버네이트의 고유 기능들은 필요할 때 부가적인 기능을 제공하는 명세나 벤더 확장의 중요 부분을 구현하고 있다. 작성한 코드가 JPA를 사용하는지 하이버네이트를 사용하는지 알 수 있는 간단한 방법은 다음과 같다. 만약 javax.persistence.* 패키지만 쓰고 있다면 명세에 따라 작업하고 있는 것이다. 만약 hibernate.* 패키지를 쓰고 있다면 하이버네이트 고유 기능을 사용하고 있는 것이다.

 

비즈니스 계층은 그 밑에 있는 영속화 계층과 의사소통하여 도메인 모델에 대한 영속 객체를 저장하고 읽어온다. ORM은 영속화를 관리하는 영속화 계층의 미들웨어에 해당한다.