0%

nodejs+sequelize数据库实操

技术栈:nodejs(type: module) + sequelize + mysql + dotenv-cli
代码仓库地址:https://gitee.com/Lxinz/db-use.git

Sequelize 基础准备

默认你已经完成docker部署mysql,并创建了db_use的数据库,设置了数据库账号root/123456。

1、如果没有安装sequelize、sequelize-cli、相关数据库(比如mysql2),需要先安装

npm install sequelize sequelize-cli mysql2

2、在对应目录下,初始化 Sequelize(生成配置、迁移、种子目录等)

npx sequelize-cli init

目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
project/
├── config/
│ ├── .env.development // 开发环境配置
│ └── .env.production // 生产环境配置
├── db/
│ ├── config/
│ │ └── config.js // 数据库配置文件
│ ├── models/
│ │ └── index.js
│ ├── migrations/
│ │ └── [timestamp]-create-users-table.js
│ └── seeders/
├── .sequelizerc
├── package.json
└── ...

3、数据库配置(用于迁移)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// config/config.js
export default {
development: {
username: process.env.DEV_DB_USERNAME,
password: process.env.DEV_DB_PASSWORD,
database: process.env.DEV_DB_DATABASE,
host: process.env.DEV_DB_HOST,
port: process.env.DEV_DB_PORT,
dialect: process.env.DEV_DB_DIALECT,
},
production: {
username: process.env.PROD_DB_USERNAME,
password: process.env.PROD_DB_PASSWORD,
database: process.env.PROD_DB_DATABASE,
host: process.env.PROD_DB_HOST,
port: process.env.PROD_DB_PORT,
dialect: process.env.PROD_DB_DIALECT,
}
};

上面使用了dotenv来读取环境变量,需要安装npm install dotenv。

这里使用了环境变量去配置数据库的信息,环境变量放置在根目录的config下(具体可查看目录结构)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# .env.development
NODE_ENV=development
DEV_DB_USERNAME=root
DEV_DB_PASSWORD=123456
DEV_DB_DATABASE=db_use
DEV_DB_HOST=localhost
DEV_DB_PORT=3306
DEV_DB_DIALECT=mysql

# .env.production
NODE_ENV=production
PROD_DB_USERNAME=root
PROD_DB_PASSWORD=123456
PROD_DB_DATABASE=db_use
PROD_DB_HOST=localhost
PROD_DB_PORT=3306
PROD_DB_DIALECT=mysql

上面环境变量通过dotenv-cli,在scripts脚本配置时,直接指向了对于目录的环境配置,因此可以在项目中直接使用process.env.NODE_ENV这样的方式调用环境变量。

1
2
3
4
5
6
7
8
9
// package.json的scripts区域中使用dotenv-cli参考
"scripts": {
"serve": "dotenv -e config/.env.development node index.js",
"serve:prod": "dotenv -e config/.env.production node index.js",
"migrate:up": "dotenv -e config/.env.development npx sequelize-cli db:migrate --env=development",
"migrate:undo": "dotenv -e config/.env.development npx sequelize-cli db:migrate:undo --env=development",
"migrate:up:prod": "dotenv -e config/.env.production npx sequelize-cli db:migrate --env=production",
"migrate:undo:prod": "dotenv -e config/.env.production npx sequelize-cli db:migrate:undo --env=production"
},

Sequelize 表迁移步骤(生产推荐使用)

1、新建一个迁移文件

npx sequelize-cli migration:generate --name create-users-table

2、手动修改迁移文件内容(修改为ES语法、添加数据库字段)

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
export default {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
name: {
type: Sequelize.STRING,
},
email: {
type: Sequelize.STRING,
unique: true,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},

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

await queryInterface.dropTable(‘Users’)作用?
用于 回滚迁移的操作(undo migration),当执行npx sequelize-cli db:migrate会运行 up() 方法,创建 Users 表;当执行npx sequelize-cli db:migrate:undo会运行 down() 方法,这时候 dropTable('Users') 就会生效,把 Users 表删掉。

需要注意的是,个迁移文件的话,db:migrate:undo 只会回滚最后一个迁移文件。如果你想一次性回滚所有迁移,则执行npx sequelize-cli db:migrate:undo:all即可。

2、项目根目录配置.sequelizerc

这样可以在项目的根目录去执行迁移指令,或者封装到package.json的scripts中也可以正常使用了。

1
2
3
4
5
6
7
8
9
10
// .sequelizerc 文件
// 注意:sequelizerc的配置文件一定要使用commonjs规范,不能使用es6规范,否则使用sequelize-cli会无法识别配置信息
const path = require('path');

module.exports = {
'config': path.resolve('db', 'config', 'config.js'),
'models-path': path.resolve('db', 'models'),
'seeders-path': path.resolve('db', 'seeders'),
'migrations-path': path.resolve('db', 'migrations'),
};

3、执行迁移

在项目根目录下执行:

npx sequelize-cli db:migrate --env=development

其中的 development 参数指的是你在 sequelize 初始化的 config/config.js 文件中配置的某一个环境;如果你不加 --env 参数,Sequelize CLI 默认使用 development 环境。

Sequelize 数据迁移-种子操作(Seed)

1、创建种子文件

npx sequelize-cli seed:generate --name update-user

2、编辑种子文件

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
export default {
async up (queryInterface, Sequelize) {
/**
* Add seed commands here.
*
* Example:
* await queryInterface.bulkInsert('People', [{
* name: 'John Doe',
* isBetaMember: false
* }], {});
*/
await queryInterface.bulkInsert('Users', [{
name: 'John Doe',
email: '12345678910@qq.com',
createdAt: new Date(),
updatedAt: new Date()
}], {});
},

async down (queryInterface, Sequelize) {
/**
* Add commands to revert seed here.
*
* Example:
* await queryInterface.bulkDelete('People', null, {});
*/
await queryInterface.bulkDelete('Users', null, {});
}
};

如果只更新表中指定的某条数据的部分字段,可以在up函数中的queryInterface.bulkInsert方法的第二个参数传入一个对象,第三个参数传入查询参数。

1
2
3
4
5
await queryInterface.bulkUpdate(
'Users',
{ name: '李四' }, // 更新内容
{ id: 1 } // where 条件
);

3、执行种子插入

npx sequelize-cli db:seed:all --env=development

增删改查实操

1、在db/models下创建对应数据库的表模型,比如User.js,内容可以参考迁移文件中对应的表进行编写。

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
export default (sequelize, DataTypes) => {
const Users = sequelize.define('Users', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
},
email: {
type: DataTypes.STRING,
unique: true,
},
}, {
// 启动时间,设置为ture会自动生成创建和更新时间,默认字段名称为createAt、updateAt。
timestamps: true,
// 对应的表名将与model名相同
freezeTableName: true,
// 表备注
comment: '用户表',
});

return Users;
};

需要注意的是,如果迁移表中创建了createdAt、updatedAt等时间自动,可以在表模型文件中通过配置属性timestamps去实现自动创建和更新,也就不需要在表模型的字段定义中再次定义了。

如果是先写了表模型文件,想编写对应的迁移文件,就需要注意,如果有timestamps字段定义的,需要在迁移文件中自行创建。

之后,会在db/models/index.js中自动引入,并导出sequelize实例和表模型的一个对象db,通过db就可以进行数据库对应表的增删改查了。

2、比如以上面创建的Users表为例,在项目的根目录的入口index.js中实现增删改查。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// index.js
import db from './db/models/index.js';
const { Users } = db;

// 增加
const newUser = await Users.create({ name: 'Tom', email: 'tom@example.com' });

// 查询
const User = await Users.findOne({ where: { email: 'tom@example.com' } });
console.log(User.toJSON());

// 更新
await Users.update({ name: 'Tommy' }, { where: { email: 'tom@example.com' } });

// 删除
await Users.destroy({ where: { email: 'tom@example.com' } });