Sequelize学习

1.安装使用

最佳实践:sequelize + sequelize-cli捆绑消费。这里介绍搭配eggjs进行使用

1
npm i egg-sequelize mysql2 sequelize-cli --save

先讨论一下配置egg-sequelize这个package。打开config目录的plugin.js文件声明使用egg-sequelize这个插件,如下所示:

1
2
3
4
5
6
7
// plugin.js
module.exports = {
sequelize: {
enable: true,
package: "egg-sequelize"
}
};

告诉egg应该使用egg-sequelize这个package之后,接着还需要配置sequelize该怎么连接database。打开config/config.default.js文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = appInfo => {
const config = exports = {};

config.sequelize = {
dialect: "mysql",
host: "127.0.0.1",
password: "YOUR_PASSWORD",
port: 3306,
database: "learn_egg"
};

return {
...config
};
};

接着在项目的根目录上面新建一个.sequelizerc文件,这个文件的作用:sequelize-cli的配置文件,可以在里面配置migration文件的路径,modal文件的路径,seeder文件的路径,数据库环境配置。内容示例如下:

1
2
3
4
5
6
7
8
const path = require("path");

module.exports = {
"config": path.join(__dirname, "database/config.json"),
"migrations-path": path.join(__dirname, "database/migrations"),
"seeders-path": path.join(__dirname, "database/seeders"),
"models-path": path.join(__dirname, "app/model")
};

注意上面我们把model文件放在app目录中,可参考egg目录结构配置这一块。

既然已经配置好了,接下来我们利用sequelize-cli来做一些事了。

1
2
### 生成配置文件
./node_modules/.bin/sequelize init:config

生成migration文件,这个migration文件可以用来数据库迁移。就好比我们使用Git来管理代码一样,migration就是用来管理数据表版本的。同时,最佳实践,不手动建表,一:建表的SQL自己要另存,用处不大,只能看看。二:写不来,不是放光的DBA。而有了sequelize-cli的帮助的话,可以,如果你想要建表的话,那么来写一个migration文件吧,不仅能够用来创建数据表,而且还能够用来进行数据表的版本回退。

1
2
### 按照配置生成migrations目录
./node_modules/.bin/sequelize init:migrations

执行上面这条bash命令后,sequelize-cli会在我们约定好的地方生成migrations目录。

2.我想要建表了

别急着定义model,在sequelize-cli中,始于migration。

1
2
### 生成某个表的migration命令
./node_modules/.bin/sequelize migration:generate --name=users

执行之后,我们可以看到在migrations目录中多了一个时间戳-users名字的js文件。要想建表的话,那么就撸起袖子在这个文件里面做操作吧。

3.我该如何使用sequelize API建表

谈到数据表,那自然离不开表字段的定义。这里只说点超超超简单的,什么表约束等不懂。字段自然是声明类型。对于migration文件来说,它是被sequelize-cli给直接处理的。所以我们讨论一下sequelize-cli,在它的建立的规则里面,migration文件导出一个对象,对象拥有两个字段,分别是up和down。up也好,down也好,他们都是一个函数,函数的第一个参数是queryInterface(可以理解为操作数据库的实例),第二个参数是Sequelize类,常用来声明类型。下面是一个示例:

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
37
38
39
40
module.exports = {
up: async (queryInterface, Sequelize) => {
const { STRING, DATE, INTEGER, TEXT } = Sequelize;
await queryInterface.createTable("news", {
id: {
type: INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
title: {
type: STRING,
allowNull: false
},
createdAt: {
type: DATE,
allowNull: false
},
updatedAt: {
type: DATE,
allowNull: false
},
author: {
type: STRING(32),
allowNull: false
},
content: {
type: TEXT,
allowNull: false
},
category: {
type: STRING,
allowNull: false
}
});
},

down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable("news");
}
};

4.我该如何利用migration文件创建一个数据表

前面也提到了,migration文件是被sequelize-cli所消化的,当写好migration文件之后,可以使用下面的命令利用migration文件来创立数据表:

1
./node_modules/.bin/sequelize db:migrate

写完migration文件之后应该做什么?写model文件,是有点繁琐。相比./node_modules/.bin/sequelize model:generate –name users –attributes …. 是繁琐了一点。但是推荐除非是特别了解SQL的话,起手还是先写migration文件吧。

如果在建立玩表后,发现有些字段考虑不周的话,那么可以使用下面命令进行回退:

1
2
3
4
### 回退到上个版本
./node_modules/.bin/sequelize db:migrate:undo
### 回退到初始状态
./node_modules/.bin/sequelize db:migrate:undo:all

5.写model文件

不同于migration文件是相当于log一样,model在后端程序中还是很重要的。首先明确一下model的职责:和数据库打交道。那个数据表?因此,一般会在model文件里面定义好数据表;打交道的时候交流一些什么内容?因此在model文件里面一般也会定义好相关的api方法来规定说话套路的。下面是一个例子:

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
37
38
39
40
const bcrypt = require("bcrypt");

/**
* egg-sequelize这个package不仅把Sequelize挂载在app实例上面了
* 而且还把Sequelize实例model(连接好了数据库)挂载在app实例上面
*/
module.exports = app => {
const { INTEGER, STRING, TINYINT } = app.Sequelize;

/** 定义好数据表 */
const User = app.model.define("User", {
email: { type: STRING(40), unique: true },
password: STRING,
username: STRING(40),
receive_remote: {
type: TINYINT(1),
defaultValue: 0
},
email_verifyed: {
type: TINYINT(1),
defaultValue: 0
}
});

/** 对密码进行加密 */
async function hashPwd(user) {
if (!user.changed('password')) return; // 加密耗时,只针对密码发生变化时候做个加密处理
user.password = await bcrypt.hash(user.password, 10);
}

User.beforeSave(hashPwd);

User.findByEmail = async function(email) {
return await this.findOne({
where: { email }
});
};

return User;
};

6.写seed文件插入数据

某些时候,我们需要模拟大量的测试数据入库,或者将大量的正式数据从模板里面读取接着入库,那么此时利用seed文件来完成这个任务便十分方便。首先键入以免命令新建seeder文件:

1
./node_modules/.bin/sequelize seed:generate --name records

然后打开生成的records这个seed文件。举例编辑如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = {
up: async (queryInterface, sequelize) => {
await queryInterface.bulkInsert("records", [{
url: "http://www.nkjx.gov.cn/news-list-jinrizhengwen.html",
startPage: 1,
endPage: 1,
date: new Date()
}], {});
},
down: async (queryInterface, sequelize) => {
await queryInterface.bulkDelete("records", null, {});
}
};

在写好了插入数据的逻辑之后,执行以下命令便可以把数据插入到库里面了:

1
./node_modules/.bin/sequelize db:seed:all