Dev/SW Engineering

33. ORM - Sequelize

HJChung 2020. 9. 5. 16:39

+ Sequelize에 대해 공부한 것을 정리한 것입니다. 배우는 중이라 잘못된  내용이 있을 수 있으며 계속해서 보완해 나갈 것입니다. :))

1. ORM이란

Object-Relational Mapping의 약자로 Object는 Javascript상의 그 '객체'가 맞다. 그리고 Relational은 Relational DB(관계형 DB)를 말한다. 

 

출처: codestates

 

이 그림과 같이 ORM을 통해 관계형 DB의 entity, record 들에 접근할 때 마치 Javascript에 있는 객체 혹은 classs를 다루듯이 취급 할 수 있다. 즉, 관계형 DB와 Javascript의 객체 사이의 통역사 역할을 담당하는 M-V-C 중 Model을 기술하는 도구이다. 

2. ORM을 사용하는 이유

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

(아래 그림)

이 때 서로의 구조 간의 불일치가 있어서 ORM을 활용하여 객체 간의 관계를 바탕으로 SQL을 자동으로 생성하여 이러한 불일치를 해결할 수 있다. 

쉽게 말하면, 
ORM을 쓰는 이유는 자바스크립트 구문을 알아서 SQL으로 바꿔주기 때문이다. 따라서 SQL언어를 직접 사용하지 않아도 자바스트립트 만으로도 MySQL(Relation DB)을 조작할 수 있다.

장점

  • 익숙한 객체 지향적인 코드를 사용할 수 있다.  ORM을 통해 작성한 객체를 재활용할 수 있다는 것은 코드의 재사용 및 유지보수가 편리해진다는 것이다. 

단점

  • 잘못 구현한 경우 성능이 저하될 수 있으므로 복잡하 쿼리문의 경우 오히려 SQL문으로 사용하는 것이 더 직관적일 수 있다.

3. Sequelize의 소개 및 사용

이번 sprint에서 사용한 ORM은 node.js 기반의 ORM인 Sequelize이다.

 

https://sequelize.org/master/

 

Sequelize를 통해 shortly 데이터베이스에 users, commnets 모델을 정의하고,

MySQL의 shortly 데이터베이스에 노드를 연동하여

 migration(스키마 변경에 따른 데이터 이주(migration)를 뜻함)을 통해

MySQL에 Sequelize의 users, commnets모델과 일치하는 users, commnets 테이블을 생성해보자. 

1) sequelize 및 sequelize-cli 설치

npm 패키지 설치

터미널

npm install

sequelize에 필요한 sequelize와 mysql2 패키지 설치

※mysql2: mysql2는 mysql와 node를 연결해주는 드라이버이다. 

터미널

npm install sequelize mysql2

sequelize 커맨드 사용을 위한 sequelize-cli 설치

터미널

npm install sequelize-cli

2) project bootstrapping

sequelize-cli를 통해 ORM을 잘 사용할 수 있도록 프로젝트 초기 단계를 자동으로 설정

터미널

npx sequelize-cli init

그러면 

  • config/config.json
  • models/
  • migrations/
  • seeders/

폴더가 생성된다. 

3) MySQL 연결

Sequelize를 통해 MySQL의 이 데이터베이스(shortly)에 노드를 연동 한다. 

sync() 메서드는 서버 실행 시 자동으로 MySQL과 연동되도록 한다. 

server/app.js

// 3) sync() 작성
// app.js 파일에서 DB 연결을 위한 sync() 메서드를 작성합니다.

const models = require('./models')

models.sequelize
  .sync()
  .then(() => {
    console.log(' DB 연결 성공')
  })
  .catch((err) => {
    console.log('연결 실패')
    console.log(err)
  })

4) 설정 파일을 이용해 MySQL 접속 설정

config.json을 원하는 MySQL 커넥션과 일치하게 수정한다.

config/config.json

{
  "development": {
    "username": "root",
    "password": "[root 비밀번호]",
    "database": "shortly",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  // test와 production쪽은 각각 테스트 용도와 배포 용도로 사용되는 것이므로 나중에 사용한다. 
}

5)  Sequelize에 모델 정의

MySQL에서 정의한 테이블을 Sequelize에서도 모델로 정의해야한다. 

Sequelize의 모델은 MySQL의 테이블과 연동되며 Sequelize는 모델과 MySQL을 연결해주는 역할을 한다. 

주의할 것은 Sequelize는 기본적으로 모델명을 단수(예. user)로 지정해주면 그에 해당하는 테이블을 복수형(예. users)으로 사용한다. 

 

공부하면서 이 부분이 헷갈렸다. MySQL과 연동이 될텐데 왜 Sequelize에도 그 테이블과 같은 형식의 모델을 왜 만들어줘야 하는거지? 싶었다. 그리고 또 모델은 뭔가?!

=> Sequelize의 모델이 MySQL의 테이블이라고 생각하면 된다. 

 

모델을 정의하는 부분에서 어떤 reference는 cli로, 어떤 곳은 sequelize.define로, 어떤 곳은 model.init으로 알려주고 있었는데, 

sequelize.org/master/manual/model-basics.html 공식홈페이지의 Model Basics 부분과

stackoverflow.com/questions/55876970/sequelize-js-whats-the-difference-between-sequelize-define-and-model-init 에서 나와 같은 의문에 대한 답변을 통해

모델은 Sequelize 에서 두 가지 동일한 방법 으로 정의 할 수 있습니다 .:

  1. Calling sequelize.define(modelName, attributes, options) API documentation on define

  2. Extending Model and calling init(attributes, options) API documentation on init

After a model is defined, it is available within sequelize.models by its model name.

As you mentioned and as stated in the documentation:

Internally, sequelize.define calls Model.init, so both approaches are essentially equivalent.

라는 것을 알 수 있었다. :))

 

모델이 정의되면 모델 이름으로 sequelize.models 내에서 사용할 수 있습니다.

모델 정의방법1. .define을 이용한 직접 작성

models/users.js

module.exports = function(sequelize, DataTypes){
    let user = sequelize.define("user", {
        name:{
        	type: DataTypes.STRING(20),
            allowNull: false,
            unique: true,
        }, 
        age: {
        	type: DataTypes.INTEGER.UNSIGNED,
            allowNull: false,
        },
        married: {
        	type: DataTypes.BOOLEAN,
            allowNull: false,
        },
        comment: {
        	type: DataTypes.TEXT,
            allowNull: true
        },
        createdAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
            
    }, {
        timestamps:false,
    });
}

models/comment.js

module.exports = function(sequelize, DataTypes){
    let user = sequelize.define("comment", {
        comment: {
        	type: DataTypes.STRING(100),
            allowNull: false,
        },
        created_at: {
        	type: DataTypes.DATE,
            allowNull: true,
            defaultValue: sequelize.literal('now()'),
        },      
    }, {
        timestamps:false,
    });
}

모델 정의방법2. model.init을 이용한 직접 작성

models/users.js

const Sequelize = require('sequelize');

module.exports = classs User extends Sequelize.Model {
  static init(sequelize){//연결 객체: model과 mysql을 연결
	return super.init({
        name:{
        	type: DataTypes.STRING(20),
            allowNull: false,
            unique: true,
        }, 
        age: {
        	type: DataTypes.INTEGER.UNSIGNED,
            allowNull: false,
        },
        married: {
        	type: DataTypes.BOOLEAN,
            allowNull: false,
        },
        comment: {
        	type: DataTypes.TEXT,
            allowNull: true
        },
        createdAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
            
    }, {
    	sequelize, //연결 객체: model과 mysql을 연결
        timestamps:false,
    });
}

models/comment.js

const Sequelize = require('sequelize');

module.exports = class Comment extends Sequelize.Model{
  static init(sequelize){
    return ssuper.init({
        comment: {
        	type: DataTypes.STRING(100),
            allowNull: false,
        },
        created_at: {
        	type: DataTypes.DATE,
            allowNull: true,
            defaultValue: sequelize.literal('now()'),
        },      
    }, {
    	sequelize,
        timestamps:false,
    });
}

모델 정의방법3. cli을 이용한 작성

터미널에 아래와 같은 형식으로 작성해주면 된다. 

터미널

sequelize model:create --name TABLE_NAME --attributes "COLUMN1:type, COLUMN2:type, COLUMN3:type"

6) migration 진행

shortly 데이터베이스 에 아직 테이블이 생성되어 있지 않고, Sequelize에 user모델을 먼저 만든 후 migration(스키마 변경에 따른 데이터 이주(migration)를 뜻함)을 통해 MySQL에 Sequelize의 user 모델과 일치하는 users 테이블을 생성하고자 한다면

sequelize.org/master/manual/migrations.html#creating-the-first-model--and-migration-에 안내 된 대로

터미널

npx sequelize-cli migration:generate --user migration-skeleton

을 해주고 

/migration

module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable('users',
      {
         name:{
        	type: Sequelize.STRING(20),
            allowNull: false,
            unique: true,
        }, 
        age: {
        	type: Sequelize.INTEGER.UNSIGNED,
            allowNull: false,
        },
        married: {
        	type: Sequelize.BOOLEAN,
            allowNull: false,
        },
        comment: {
        	type: Sequelize.TEXT,
            allowNull: true
        },
        createdAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
      })
  },
  down: async (queryInterface, Sequelize) => {
    await queryInterface.dropTable('users');
  }
};

위와 같이 migration skeleton 코드를 작성해준다.  (※up/down의 개념과 사용법에 대해서는 (여기서 url첨부) 자세히 정리할 것이다.)

 

그리고 migration을 해주면!

터미널

npx sequelize-cli db:migrate

이렇게 결과가 잘 나오면서 mySQL에 테이블이 잘 생성된 것을 확인 할 수 있다. 

(캡쳐 사진 넣기)

 

지금까지

"mySQL에 Sequelize를 통해 shortly 데이터베이스에 users, commnets 모델을 정의하고,

MySQL의 shortly 데이터베이스에 노드를 연동하여

 migration(스키마 변경에 따른 데이터 이주(migration)를 뜻함)을 통해

MySQL에 Sequelize의 users, commnets모델과 일치하는 users, commnets 테이블을 생성해보았다." 

이제 Sequelize ORM을 이용하여 Client-Server-Database의 상호 작용을 가능하게하는 준비가 되었다. 

 

다음 포스트에는 MVC design pattern을 적용하고, Sequelize을 통해 데이터를 주고 받을 수 있도록 구현해본 과정을 정리해 볼 것이다.

 

reference

Node.js 교과서 - 조현영 지음

sequelize.org/

sequelize.org/master/manual/migrations.html

sequelize.org/master/manual/migrations.html#project-bootstrapping

jongmin92.github.io/2017/04/08/Node/sequelize/

victorydntmd.tistory.com/27

sequelize.org/master/manual/migrations.html#creating-the-first-model--and-migration-

 

Manual | Sequelize

Migrations Just like you use version control systems such as Git to manage changes in your source code, you can use migrations to keep track of changes to the database. With migrations you can transfer your existing database into another state and vice ver

sequelize.org

+ Sequelize에 대해 공부한 것을 정리한 것입니다. 배우는 중이라 잘못된  내용이 있을 수 있으며 계속해서 보완해 나갈 것입니다. :))