我感觉使用任何一门语言作为后台开发都应该了解他的 ORM(Object Relational Mapping) 框架,这是对开发效率的负责,省掉写 Sql 的时间,把它留给更有意义的地方。
本篇以 Mysql 数据库为例,带大家了解 Node 中最多人用的 ORM 框架 Sequelize
下载
npm1
2$ npm install sequelize --save
$ npm install mysql2 --save
yarn1
2$ yarn add sequelize
$ yarn add mysql2
创建连接
使用配置1
2
3
4
5
6
7
8
9
10
11const Sequelize = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'mysql',
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
});
使用连接URI1
const sequelize = new Sequelize('postgres://user:[email protected]:5432/dbname');
Sequelize 更多用法见 API
创建 Model
首先使用执行下面的语句创建一个测试表 test
1
2
3
4
5
6CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL DEFAULT '',
`create_ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='test';
接下来创建 Model1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16const Test = sequelize.define('test', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: {
type: Sequelize.STRING
},
create_ts: {
type: Sequelize.DATE
}
},{
timestamps: false,
freezeTableName: true,
});
更多 dataTypes 以字段检查 validationsdefine
方法的前两个参数比较好理解,第一个是表名,第二个定义了表中字段的映射关系,第三个比较有意思,待会儿我们在聊它的作用。
使用 Model
首先来创建一条数据,需要用到 build(), save()
两个方法1
2
3Test.build({name: "wxnacy"}).save()
.then(() => {sequelize.close()})
.catch(() => {sequelize.close()})
save()
方法回来一个 Premise ,并且必须在结束时加上 sequelize.close()
方法关闭连接,目前我还没找到自动关闭的地方,如果你知道,一定要告诉我。
查询1
2
3
4
5
6Test.findOne({where: {name: 'wxnacy'}}).then(test => {
console.log(test.id, test.name) // 1 wxnacy
sequelize.close()
}).catch(e => {
sequelize.close()
})
这种查询方式很简洁,写起来很爽,跟 Rails
很像,这时我们可以来说说前边创建 Model 时提到的 timestamps, freezeTableName
两个参数的作用,你去掉这两个参数在执行一次,它会报错,日志中给出的 Sql 语句是这样的1
SELECT `id`, `name`, `create_ts`, `createdAt`, `updatedAt` FROM `tests` AS `test` WHERE `test`.`name` = 'wxnacy' LIMIT 1;
两个奇怪的点,凭空多出了 createAt, updateAt
两个字段,原表名默认来 tests
,Sequelize 很“贴心”,直接将表名加了个复数,也把我们表中最常用的两个字段也默认加了进去,BUT,表名我就不想加复数,我的创建时间修改时间也不打算叫这个名字,所以这里需要一些额外的控制
- freezeTableName 是否将表名默认使用
define()
的第一个参数,默认 false - tableName 自定义表名
- timestamps 控制是否添加(createAt,updateAt)两个字段,默认 true
- createdAt 如果
timestamps
等于 true,可以设置这个参数,false 为不添加,或者可以为它设置别名,比如create_ts
- updatedAt 同上
- deletedAt 同上
我知道你想说什么,如果每个 Model 都这样设置那是要累死的,所以他必须要有一个可以设置全局的地方,比如1
2
3
4
5
6const sequelize = new Sequelize(db, user, pw, {
define: {
timestamps: false,
freezeTableName: true,
}
})
更多的 define 配置请见文档
好了,我们来写一个完整的例子吧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
36const Sequelize = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'mysql',
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
});
const Test = sequelize.define('test', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: {
type: Sequelize.STRING,
allowNull: true,
defaultValue: ''
},
create_ts: {
type: Sequelize.DATE
}
});
Test.build({name: "wxnacy"}).save()
.then(() => {
return Test.findById(1)
}).then(item => {
console.log(item.id, item.name); // 1 wxnacy
sequelize.close()
}).catch(e => {
console.log(e);
sequelize.close()
})
常用的方法
1 | Test.create({name: "wxnacy"}) |
Model 更多使用方法见文档