프로그래밍

ORM vs ODBC

2kindsofcs 2020. 2. 24. 17:07

기존에 토이프로젝트를 node.js 기반으로 작업했었는데, sequelize를 사용했다. 

이번에 golang으로 간단한 서버를 짜면서 sqlx를 사용했는데,

sequelize가 보유했던 기능들이 있을 거라 생각했지만 그건 착각이었다. 

애초에 sqlx는 orm이 아니다. 

 

각 프로젝트의 깃헙 메인 README에 친절하게 적혀있다.

 

아래는 sqlx 저장소 README의 첫 문장이다.

sqlx is a library which provides a set of extensions on go's standard database/sql library.

sqlx는 ORM이 아니다.

sqlx는 go에 기본 라이브러리인 database/sql을 기반으로 확장된 기능을 제공한다고 적혀있다. 

 

 

아래는 sequelize 저장소 README의 첫 문장이다.

Sequelize is a promise-based Node.js ORM for Postgres, MySQL, MariaDB, SQLite and Microsoft SQL Server. 

sequelize는 promise-based ORM임을 명시하고 있다. 

 

 

1. ORM

 

이제 ORM에 대해 알아보자.

우리의 친구 위키피디아에는 이렇게 나와 있다.

객체 관계 매핑(Object-relational mapping; ORM)은 데이터베이스와 객체 지향 프로그래밍 언어 간의 호환되지 않는 데이터를 변환하는 프로그래밍 기법이다. 객체 지향 언어에서 사용할 수 있는 "가상" 객체 데이터베이스를 구축하는 방법이다. 객체 관계 매핑을 가능하게 하는 상용 또는 무료 소프트웨어 패키지들이 있고, 경우에 따라서는 독자적으로 개발하기도한다.

데이터베이스에서 읽어온 데이터를 객체에 mapping하겠다는 것이다. 

ORM은 DB에 있는 데이터를 객체화 시켜서 (보통 RDB는 테이블이 하나의 객체가 되도록),

그 객체를 조작하는 것으로 DB를 조작할 수 있게 해준다. 

 

place라는 데이터테이블이 있다고 가정하자. 이 테이블에는 country, city, telcode 세 가지 필드가 있다.

sequelize에서는 이 place를 Place라는 클래스로 만들어서 사용할 수 있다.  

 

예를 들어, 아래와 같이 place라는 테이블의 모든 row를 조회할 수 있다.

// db 연결 및 모델 설정은 다 했다고 가정
const placeList = await Place.findAll();

 

 

sequelize의 findAll 메소드는 Promise<Array<Model>>을 리턴한다.

placeList는 (promise가 잘 resolve 되었다면) Place 인스턴스의 어레이다.

 

for cosnt place of placeList {
	console.log(place.country)
	console.log(place.city)
	console.log(place.telcode)
}

 

위는 각각의 Place model 인스턴스에 접근하여 원하는 필드 값들을 활용할 수 있음을 보여주기 위한 간략한 예시이다. 

실제로는 console.log가 아닌 다양한 로직을 이용해 인스터스를 활용하는 경우가 훨씬 많을 것이다. 

 

 

 

sqlx에서는 어떨까? sequelize에서처럼 어떤 테이블을 객체화시켜서 활용할 수 있을까?

sequelize의 findAll처럼 모든 place 테이블의 모든 row를 읽는 상황을 가정해보자. 

아래 코드는 Illustrated Guid to SQLX의 Query부분의 예제 코드이다.

 

// fetch all places from the db
rows, err := db.Query("SELECT country, city, telcode FROM place")
 
// iterate over each row
for rows.Next() {
    var country string
    // note that city can be NULL, so we use the NullString type
    var city    sql.NullString
    var telcode int
    err = rows.Scan(&country, &city, &telcode)
}

 

답은 "아니오"다. 애초에 테이블을 객체처럼 조작할 수 없다. 

 

You should treat the Rows like a database cursor rather than a materialized list of results.

 

그리고 위 예제 코드의 경우,

쿼리 결과물의 리스트를 얻을 수 있는 게 아니라 Scan을 이용해 우리가 원하는 결과를 한 행씩 읽어들이는 것에 가깝다.

 

 

2. ODBC

 

그렇다면 ODBC는 뭘까? ODBC는 어떤 dbms를 쓰는지와 상관없이 응용프로그램이 동일한 api로 통신할 수 있게 해준다. 

ORM도 dbms랑 상관없이 db를 조작할 수 있다. 그러면 ODBC와 ORM은 동일한가? 

 

답은 "아니오"다. 

ODBC의 핵심은 "dbms와 상관없이 동일한 api로 통신한다"는 것이다. DB에 있는 데이터를 객체화시키는 것과는 관련이 없다.

고로 직접 findAll같은 메소드를 사용하는 것이 아니라 직접 쿼리를 작성해야 한다. 

 

반응형