Sequelize 是一个基于 Node.js 的 ORM 库。
ORM 全称:Object Relational Mapping - 对象关系映射,是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。说简单一些,就是像操作对象一样去操作数据库,而不是 SQL 。
Sequelize-cli 是其中的一个独立的工具,提供了一些快速操作数据库的功能。比如:创建数据库、创建表等……。
首先,我们需要安装 Sequelize-cli
npm i -D sequelize-cli仅仅有这个工具还不够,应该需要设计到数据库的具体操作。所以,我还要安装 Sequelize(它们就像是 vue-cli/Vue、create-react-app/React 之间的关系)。而且 Sequelize 在我们的项目里面还要使用的,所以就安装它。
npm i sequelize最后,Sequelize 是对 MySQL、MSSQL 等数据操作的一种抽象封装,提供了统一的 API,实际具体的数据库操作需要我们独立安装对应的库,比如,我们要操作的是 MySQL ,那么我们需要安装 mysql2 这个独立的模块。
npm i mysql2首先,我们先来了解几个概念,同时通过这几个概念来了解这个工具到底是做什么的。
迁移种子迁移的功能类似于 Git 。通过它,我们可以追踪数据库的状态以及变更记录,我们会把这些信息存储到指定的文件中,然后执行指定的命令来更新数据库或者恢复到某个原有状态。
有的时候,我们需要为数据库写入一些测试数据,那么这个时候,我们就可以通过种子来完成这个需求。
我们在根目录下创建一个文件:.sequelizerc ,这是我们使用 Sequelize-cli 工具的时候读取的配置文件。
// file: backend/.sequelizerc const path = require('path'); module.exports = { 'env': 'development', 'config': path.resolve('src', 'configs/database.json'), 'migrations-path': path.resolve('src', 'database/migrations'), 'seeders-path': path.resolve('src', 'database/seeders'), 'models-path': path.resolve('src', 'database/models'), 'debug': true };设置 Sequelize 的环境变量,默认读取系统的环境变量 NODE_ENV 的值,如果不存在 NODE_ENV 则为 development。该变量会影响下面 config 的读取。
Sequelize 数据库配置文件存放目录。
数据库迁移脚本文件存放目录。
数据库种子脚本文件存放目录。
数据库模型文件存放目录。
是否显示详细的 debug 信息。
按照上面 .sequelizerc 中的配置,我们在 backend/src/configs 目录下创建一个 database.json 的数据库配置文件,它主要提供链接数据库所需要的一些配置。
{ "development": { // 数据库服务器主机 "host": "127.0.0.1", // 数据库类型 "dialect": "mysql", // 数据库服务器连接用户名 "username": "root", // 数据库服务器连接密码 "password": "123456", //注意这里的密码需要用引号包裹 // 数据库名称 "database": "todolist_development" }, "test": { // 测试环境下的配置... "host": "127.0.0.1", "dialect": "mysql", "username": "root", "password": "123456", "database": "todolist_development" }, "production": { // 生成环境下的配置... "host": "127.0.0.1", "dialect": "mysql", "username": "root", "password": "123456", "database": "todolist_development" } }正如我们看到的,配置文件中默认会有三个不同环境的配置:development、test、production,分别对应:开发环境、测试环境、生产环境(我们也可以根据具体情况增减),它会根据 .sequelizerc 中的 env 的值读取不同的环境下的配置 。
做好以上的一些准备工作以后,下面我们就开始来使用 Sequelize-cli 来帮助我们完成第一个工作:创建数据库。
这条命令可以帮助我们根据当前 env 值找到对应 database.json 中的配置,最后根据 database 项创建对应的数据库。
// package.json "scripts": { ..... "db:create":"sequelize db:create" }运行: npm run db:create
这条命令是删除对应数据库的。
// package.json "scripts": { ..... "db:drop":"sequelize db:drop" }运行: npm run db:drop
有了数据库,下面就需要在数据库中创建我们应用所需要用到的各种表以及表结构(字段)。这个时候就轮到前面提到的迁移脚本上场了!
首先,我们需要在前面定义的迁移脚本目录下创建一些迁移脚本,通常我们会为每一个表每次变更创建一个独立的迁移脚本。我们可以手动直接创建,也可以使用命令来创建。
使用这个命令,它可以自动在 migrations 目录下创建一个 时间-迁移文件名.js 的脚本文件。
迁移文件的名称最好能比较直观的体现它的作用和目的。比如:UserInit,表示这是一个初始化 User 表的操作。
后续如果对 User 表进行更改,比如增加了一个用户状态的字段,那么可以创建一个 UserAddStatus 的迁移脚本文件。
终端输入:./node_modules/.bin/sequelize migration:create --name UserInit脚本其实就是一个 Node.js 代码,提供给 sequelize-cli 进行读取执行,每一个脚本通过 module.exports 导出一个包含了 down 和 up 方法的对象
up:执行迁移命令(db:migrate)的时候调用down:执行撤销/回滚命令(db:migrate:undo)的时候调用Sequelize 提供了一个 queryInterface 对象,该对象下又提供了许多操作数据库结构的各种方法(DDL),如:创建表、字段、索引等。
Sequelize 的核心类,提供了一些数据库相关的常量信息,比如数据类型,也可以进行实例化,用于对数据库中的数据进行操作(DQL、DML)。
在 up 方法中,我们主要编写的创建表结构,或者新增修改表结构的相关代码。
up: (queryInterface, Sequelize) => { /* up 需要返回一个 Promise queryInterface.createTable 方法用于创建表 - 第一个参数是要创建的表的名称 - 第二个参数是一个对象,用来描述表中包含的字段信息 - queryInterface.createTable 返回一个 Promise */ return queryInterface.createTable('User', { //返回promise对象 id: { // 字段类型:数字 type: Sequelize.INTEGER, // 设置为主键 primaryKey: true, // 自动增长 autoIncrement: true }, name: { // 字符串类型(20长度) type: Sequelize.STRING(20), // 值唯一 unique: true, // 不允许 null 值 allowNull: false }, password: { // 字符串类型(32长度) type: Sequelize.STRING(32), // 不允许 null 值 allowNull: false }, createdAt: { // 日期类型 type: Sequelize.DATE, // 不允许 null 值 allowNull: false } }); }type
字段类型,Sequelize 中支持的类型列表,参考后面的 DataTypes 。
primaryKey
是否为主键。
autoIncrement
自动增长。
unique
值唯一。
allowNull
是否允许 Null 值,一般最好不要使用 Null。
defalutValue
默认值。
命令执行成功以后,我们就可以在数据库中看到对应的表以及字段信息了。
操作成功的同时数据库中会有一个叫做 SequelizeMeta 的表,这个表是用来记录我们已经执行过的迁移脚本的。当我们执行迁移命令的时候,它就会把当前执行的迁移脚本记录到该表中,下次执行迁移命令的时候就不会重复的去执行已经执行过的迁移脚本了。
撤销/回滚 其实就是编写对应的 down 脚本。
down 方法的本质就是 up 方法的一个反向操作。
down: (queryInterface, Sequelize) => { // 删除 user 表 return queryInterface.dropTable('User'); }单次撤销(最近的一次)
sequelize db:migrate:undo撤销所有
sequelize db:migrate:undo:all许多时候,因为项目需求的变更,数据库也需要修改更新。比如,当用户修改信息的时候,我们希望记录下来最后一次修改更新的时间,也就是需要给 user 表新增一个 updatedAt 字段。
添加一个新的迁移脚本
sequelize migration:create --name UserAddUpdatedAt 终端->./node_modules/.bin/sequelize migration:create --name UserAddUpdatedAt脚本
module.exports = { up: (queryInterface, Sequelize) => { // 给 User 表添加列(字段):updateAt return queryInterface.addColumn('User', 'updatedAt', { type: Sequelize.DATE, allowNull: false }) }, down: (queryInterface, Sequelize) => { // 删除 user 表的 updatedAt 列(字段) return queryInterface.removeColumn('User', 'updatedAt'); } };再次执行命令
sequelize db:migrate成功以后,数据库中的 user 表中,就会多出一个新的字段:updatedAt
原因:构建项目中需要使用到的一些测试数据。
这就要用到 Sequelize-cli 提供的种子:seeder 脚本。
执行种子文件生成命令
sequelize seed:create --name UserInit ./node_modules/.bin/sequelize seed:create --name UserInit与 migration 脚本类似,它也有 up 与 down。
const crypto = require('crypto'); module.exports = { up(queryInterface, Sequelize) { let md5 = crypto.createHash('md5'); let password = md5.update('123456').digest('hex'); let date = new Date(); return queryInterface.bulkInsert('User', ['zMouse', 'mt', 'leo', 'reci'].map((name, index) => { return { id: index + 1, name, password, createdAt: date, updatedAt: date } })); }, down(queryInterface, Sequelize) { return queryInterface.bulkDelete('User', null, {}); } };bulkInsert
批量插入数据
bulkDelete
批量删除
执行命令
sequelize db:seed:all撤销/回滚
sequelize db:seed:undo:all同迁移脚本一样,根据项目表结构,使用种子脚本生成一批数据。
我们给 package.json 的 scripts 添加几个简化命令来自动执行迁移和种子脚本。
// file: backend/package.json "script":{ // ... "db:init": "sequelize db:create && sequelize db:migrate && sequelize db:seed:all", "db:redo": "sequelize db:drop && npm run db:init" }db:init
初始化,创建数据库->执行迁移->执行种子。
db:redo
重构。