ORM (Object-Relational Mapping)
Object-Relational Mapping, 객체-관계 매핑
ORM은 객체와 RDB의 데이터를 자동으로 매핑(연결)해주는 것을 말합니다.
예를 들면, 객체 지향 언어에서는 모델을 정의할 때 Class를 사용하고, RDB에선 Table을 사용합니다.
이 떄, 객체 지향 언어로 된 Class를 RDB의 Table와 연결시켜주는 것으로 SQL문이 아닌 객체 지향 코드로 작성할 수 있습니다.
장점
- 객체 지향적인 코드로 작성하므로 직관적
- 재사용 및 유지보수의 편리성 증가
Sequelize
Sequelize는 Postgres, MySQL, MariaDB, SQLite, Microsoft SQL Server를 지원하는 Promise 패턴 기반의 Node.js ORM입니다
Spring의 JPA/Hibernate, Django의 Django ORM
ORM의 특징은 특정 DB에 종속되지 않는다는 것입니다.
즉, DB와 커넥션만 연결되면 어떤 DB를 사용하던지 상관없이 동일한 메서드로 쿼리 수행이 가능합니다.
설치
1
npm i sequelize
sequelize과 Mysql 연결
Sequelize를 사용하기 위해서는 Postgresql , MySQL , MSSQL, SQLite 등의 RDB가 시스템에 설치되어있어야 합니다.
Mysql을 연결해보겠습니다.
1
npm i mysql2
sequelize-cli
sequelize-cli 모듈은 sequelize를 조금 더 효율적으로 사용하기 위한 뼈대를 구축해줍니다.
1
npm i sequelize-cli
설치가 완료되면 sequelize 명령어를 실행할 수 있습니다.
1
sequelize init
명령 실행하면 config, models, migrations, seeders 폴더가 생성됩니다.
models/index.js
sequelize-cli가 자동으로 생성해주는 코드는 에러가 발생하기도 하고 불필요한 부분이 많아 간단하게 새로 작성해줍니다.
참고 글 : Sequelize - Getting Started
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const Sequelize = require("sequelize");
const env = process.env.NODE_ENV || "development"; // 지정된 환경변수가 없으면 'development'로 지정
const config = require("../config/config.json")[env];
// config.json 파일에 여러 변수명으로 객체를 생성하여 DB 설정을 관리합니다.
// config객체의 env변수(development)키 의 객체값들을 불러옵니다.
// 즉, 데이터베이스 설정을 불러오는 것
const db = {};
// new Sequelize를 통해 MySQL 연결 객체를 생성합니다.
const sequelize = new Sequelize(
config.database,
config.username,
config.password,
config
);
// 연결객체를 나중에 재사용하기 위해 db.sequelize에 넣어줍니다.
db.sequelize = sequelize;
module.exports = db;
config/config.json
DB 설정을 관리하는 파일입니다.
사용할 DB 정보를 입력해줍니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"development": {
"username": "root",
"password": null,
"database": "database_production",
"host": "127.0.0.1",
"dialect": "mysql"
},
"test": {
"username": "root",
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"production": {
"username": "root",
"password": null,
"database": "database_production",
"host": "127.0.0.1",
"dialect": "mysql"
}
}
모델 정의하기
Sequelize에서 모델을 정의하는 데 사용되는 메서드에는 define과 init이 있습니다.
Model에서 클래스로 구현할 것이므로 init 메서드를 사용해보겠습니다.
define은 sequelize 객체를 직접 호출하여 모델을 정의합니다.
init은 모델 클래스를 확장한 후에 호출하여 모델을 초기화합니다.
주요 매개변수
attributes : 테이블의 열(컬럼)을 정의하는 객체입니다.
각 열은 이름, 데이터 유형, 제약 조건 등을 포함합니다.
- type : 데이터 타입 명시
- primaryKey : 기본 키 설정
- allowNull : Null 허용 여부
- unique : 중복 값 저장 여부
- autoIncrement : Auto Increase 기능 사용 여부
- defaultValue : 기본 값 명시
- validate : 유효성 검사 옵션
options : 모델의 추가적인 설정을 지정하는 객체입니다.
- modelName : 모델 이름 명시적 설정
- tableName : 테이블 이름 명시적 설정
- freezeTableName : true 설정 시, 모델이름 변환 X, 지정한 이름 사용
- underscored : true 설정 시, 카멜케이스 대신 스네이크케이스를 사용
- timestamps : true 설정 시, created_at, updated_at 컬럼이 생성되며 데이터의 생성, 수정 시 시간이 자동으로 입력됩니다.
- paranoid : true 설정 시, deletedAt 컬럼이 생성되며 지운 시각이 입력됩니다.
- charset : 인코딩
models/users.js
models 폴더에 users.js 파일을 생성합니다.
class로 모듈화하고 import/export를 활용해 사용해보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// users.js
import { DataTypes, Model } from "sequelize";
class User extends Model {
static init(sequelize) {
return super.init(
// 부모 객체의 init을 사용하므로 super.init 사용
{
user_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
// unique
// defaultValue
// validate
},
password: {
type: DataTypes.STRING(30),
allowNull: false,
},
},
{
sequelize, // Sequelize 인스턴스
timestamps: false, // true : created_at, updated_at 컬럼이 생성되며 데이터의 생성, 수정 시 시간이 자동으로 입력됩니다.
paranoid: false // true : deletedAt 컬럼이 생성되며 지운 시각이 기록됩니다. ,
underscored: true, // true : 카멜케이스 대신 스네이크케이스를 사용
freezeTableName: true, // 모델이름 변환 X, 지정한 이름 사용
modelName: "User", // 모델 이름 명시적 지정
tableName: "users", // 테이블 이름 명시적 설정
}
);
}
}
export default User;
sequelize의 자료형 (DataTypes)
sequelize의 자료형은 MySQL과 다르므로 확인 후 사용해야합니다.
참고 글 : Sequelize - Datetypes
models/index.js 수정
index.js 파일에 users.js 파일을 import한 후 연결해보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const Sequelize = require("sequelize");
const env = process.env.NODE_ENV || "development"; // 지정된 환경변수가 없으면 'development'로 지정
// ************* 추가된 부분 ***************
// 클래스를 불러온다.
import User from "./users.js";
// ****************************************
const config = require("../config/config.json")[env];
// config.json 파일에 여러 변수명으로 객체를 생성하여 DB 설정을 관리합니다.
// config객체의 env변수(development)키 의 객체값들을 불러옵니다.
// 즉, 데이터베이스 설정을 불러오는 것
const db = {};
// new Sequelize를 통해 MySQL 연결 객체를 생성합니다.
const sequelize = new Sequelize(
config.database,
config.username,
config.password,
config
);
// 연결객체를 나중에 재사용하기 위해 db.sequelize에 넣어줍니다.
db.sequelize = sequelize;
// ************* 추가된 부분 ***************
// 모델 클래스를 넣어줍니다.
db.User = User;
// 모델과 테이블 종합적인 연결이 설정된다.
User.init(sequelize);
// ****************************************
module.exports = db;
모델과 DB 동기화
sync()
는 Promise를 반환하는 함수이며 이를 이용해 Model을 DB와 동기화 할 수 있습니다.
호출 시, Sequelize는 자동으로 DB에 대한 SQL 쿼리를 수행합니다.
이 떄, DB의 테이블만 변경합니다,
sync(options: object)
형태로 사용합니다.
options
미설정
: 존재하지 않는 경우에만 테이블을 생성합니다.force
: true 설정 시, 테이블을 이미 존재하는 경우 먼저 삭제한 후 생성합니다.데이터도 같이 삭제됩니다.
alter
: 테이블의 현재 상태를 확인한 후 모델과 일치하도록 변경합니다.데이터도 그대로 유지됩니다.
app.js
sequelize.sync()
를 이용하면 자동으로 모든 모델을 동기화할 수 있습니다.
app.js 파일에 index.js 파일을 import한 후 연결해보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import express from "express";
import "dotenv/config";
import db from "./models/index.js";
const app = express();
app.set("port", process.env.PORT || 8000);
try {
await db.sequelize.sync();
console.log("데이터베이스 연결됨.");
} catch (err) {
console.log(err);
}
app.use(express.json()); // json 파싱
app.use(express.urlencoded({ extended: false })); // uri 파싱
app.get("/", (req, res) => {
res.json({ message: "hello world" });
});
// 서버 실행
app.listen(app.get("port"), () => {
console.log(app.get("port"), "번 포트에서 대기 중");
});
연결 테스트
에러 없이 users 테이블이 잘 생성된 것을 확인할 수 있습니다.