Object Relational Mapping

Hoony·2022년 7월 17일
0
post-thumbnail

ORM이란?


Object Relational Mapping의 줄임말로 객체와 관계형 데이터베이스를 자동으로 매핑해주는 것을 말한다.

객체지향 프로그래밍은 클래스를 사용하고, 관계형 데이터베이스는 테이블을 사용한다.

한마디로, 객체 모델과 관계형 모델은 불일치가 존재하고 이는 객체지향 프로그래밍에서 데이터베이스를 다루기 어렵게 만든다.

ORM은 이러한 불일치를 해소하고자 나온 기법이다.

ORM을 통해 자동으로 객체랑 데이터베이스 데이터를 매핑해주기 때문에 우리는 객체지향 프로그래밍처럼 데이터베이스를 다룰 수 있다.



ORM의 장점


객체지향적 접근 가능

ORM을 이용하면 SQL문이 아닌 객체지향 프로그래밍 패러다임을 그대로 가져와 객체의 프로퍼티와 메서드를 통해 데이터베이스 조작이 가능하다.
기존에는 SQL의 절차적 접근 방식과 프로그래밍 언어의 객체지향적 접근 방식이 혼재되어 있어서 매우 혼란스러웠다.
하지만 ORM은 개발자가 객체 모델만을 이용하여 프로그래밍에 집중할 수 있게하여 개발 생산성을 높여준다.


재사용 및 유지보수 편리성 증가

ORM은 독립적인 객체로 데이터를 다루고 해당 객체들을 재활용 할 수 있다.
따라서 재사용과 유지보수 편리성이 대폭 증가했다.


DBMS에 대한 종속성이 줄어든다.

ORM은 객체 간의 관계를 바탕으로 테이블을 자동으로 생성한다.
따라서 개발자는 객체에 집중할 수 있고 극단적으로 DBMS를 교체하는 거대한 작업에도 비교적 적은 리스크와 시간이 소모된다.



ORM의 단점


ORM만으로 완벽한 서비스를 구현하기 어렵다.

ORM은 사용하기 간편하고 빠른 개발이 가능하지만 설계를 할 때 매우 신중하게 해야한다.
잘못 구현될 경우 N+1문제 때문에 수많은 SQL문이 발생하여 심각한 성능저하를 일으킬 수 있다.

N+1문제란?

연관 관계에서 발생하는 이슈로 연관 관계가 설정된 엔티티를 조회할 경우에 조회된 데이터 갯수(n) 만큼 연관관계의 조회 쿼리가 추가로 발생하여 데이터를 읽어오게 된다. 이를 N+1 문제라고 한다.

따라서 대형 프로젝트에선 성능 개선을 위해 별도의 튜닝이 필요하다.


프로시저가 많은 시스템에선 ORM의 장점을 활용하기 어렵다.

이미 프로시저가 많은 시스템에선 다시 객체로 바꿔야하며, 그 과정에서 생산성 저하나 리스크가 많이 발생할 수 있다.


객체-관계 간의 불일치

ORM으로도 다음과 같은 이유들로 인해 객체-관계 간의 불일치가 발생한다.

1. 세분성(Granularity)
경우에 따라서 데이터베이스에 있는 테이블 수보다 더 많은 클래스를 가진 모델이 생길 수 있다.

2. 상속성(Inheritance)
RDBMS에는 객체지향 프로그래밍 언어의 특징인 상속 개념이 없다.

3. 일치(Identity)
RDBMS는 primary key를 통해 동일성을 정의한다.
그러나 프로그래밍 언어는 객체 식별과 객체 동일성을 모두 정의한다.
RDBMS에서는 PK가 같아야 동일한 데이터로 정의하지만, Java에서는 내용이 같아도 같은 경우라고 정의한다.

4. 연관성(Association)
객체지향 언어는 방향성이 있는 객체의 참조를 사용하여 연관성을 나타낸다.
그러나 RDBMS는 방향성이 없는 외래키를 통해 나타낸다.

5. 탐색(Navigation)
객체를 접근하는 방법이 근본적으로 다르다.
자바는 그래프 형태로 하나의 연결에서 다른 연결로 넘어가면서 탐색한다.
그러나 RDBMS에서는 JOIN을 통해 여러 엔티티를 가져오고 특정 엔티티를 선별하는 방식으로 탐색한다.



연관관계 방향성


객체 관계는 방향성이 존재하지만 데이터베이스 테이블에는 방향성이 존재하지 않는다.
따라서 객체지향 패러다임을 유지하기 위해서 단방향과 양방향의 차이점을 명확히 구분할 줄 알아야 한다.

단방향

객체지향 패러다임에서는 위와 같이 한 객체에서만 다른 객체를 참조하는 단방향 관계가 있다.
하지만 이 관계를 실제 테이블로 구현하면 단방향은 존재하지 않고 외래키를 통해 서로 탐색이 가능한 양방향 관계만이 존재한다.



양방향

이번에는 Member -> Team 참조가 가능하고 Team -> Member 참조가 가능한 양방향 관계이다.
어찌보면 실제 테이블과 같은 양방향 관계라 별 문제가 없이 보일 수 있지만 내부적으로 파고들면 이 둘은 다른 관계이다.


실제 Member와 Team은 관계는 양방향이 아닌 단방향 2개가 합쳐진 형태이다.
즉, Member-> Team 단방향 관계와 Team -> Member 단방향 관계가 합쳐져 양방향처럼 보일 뿐이지 실제 테이블의 양방향과는 다른 관계이다.


테이블에서는 한 쪽의 외래키를 통해 양방향 탐색이 가능하다.
하지만 객체에서는 서로에 대한 참조 값이 있어야만 탐색이 가능하다.

즉, 테이블에서는 하나의 외래키, 객체에서는 서로에 대한 참조값 2개로 이루어져 차이점이 발생한다.



연관관계 주인


앞 서 말했듯이 객체에서 양방향 관계는 두 개의 참조값이 필요하지만
실제 테이블에는 하나의 외래키만이 존재한다.

외래키를 두 개로 나눌 순 없으니 결국 한 객체에 외래키를 할당해야만 하는 문제가 발생한다.
따라서 이러한 패러다임 차이를 해결하고자 ORM에서는 연관관계의 주인을 정한다.


연관관계의 주인은 외래키를 관리하는 주체이다.
만약 이 연관관계의 주인이 없다면 ORM은 누구의 참조값이 바뀌었을 때 참조값을 바꿔야 하는지 혼란이 생긴다.

1. Member -> Team 참조값 바꾼 경우
2. Team -> Member 참조값 바꾼 경우

ORM은 두 가지 경우에서는 한 가지 경우만 참조값이 바뀌도록 정해야만 한다.
그리고 그 기준을 연관관계 주인이라고 한다.


양방향 매핑 규칙

1.객체의 두 관계중 하나를 연관관계의 주인으로 지정
2. 연관관계의 주인만이 외래키를 관리(등록, 수정)
3. 주인이 아닌쪽은 읽기만 가능



누굴 연관관계 주인으로 해야하는가?


일반적으로 실제 DB 테이블에서 외래키가 있는 쪽은 연관관계 주인으로 정한다.
이에 대한 이유는 다음과 같다.


직관적

위의 예시에서 만약 Team이 연관관계 주인이 된다면?
Team에서 참조값을 변경하면 해당 쿼리는 Member 테이블에서 날라간다.
이는 쿼리를 발생시키는 객체와 실제 쿼리의 대상이 달라 직관적이지 않다.


성능 문제

위에서 말한 것처럼 Team에서 Member 참조 값을 바꾸면 쿼리는 Member로 날아가게 된다.
즉, 이미 가져온 Team 테이블에 쿼리문을 날릴 수 없으므로 결국 Member로 다시 쿼리문을 날리게 되므로 성능 문제가 발생한다.

profile
Just Do it!

0개의 댓글