目标:
使用egg配合Sequelize连接mysql数据库
准备工作:
1、初始化项目,安装brew和mysql
(1)安装brew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
(2)安装mysql
brew install mysql
brew services start mysql
(3)通过 npm 初始化一个项目:
> $ mkdir sequelize-project && cd sequelize-project
> $ npm init egg
> --type=simple $ npm i
(4)安装并配置 egg-sequelize 插件(它会辅助我们将定义好的 Model 对象加载到 app 和 ctx 上)和 mysql2 模块:
安装
npm install --save egg-sequelize mysql2
在 config/plugin.js 中引入 egg-sequelize 插件
exports.sequelize = {
enable: true,
package: 'egg-sequelize',
};
在 config/config.default.js 中编写 sequelize 配置
config.sequelize = {
dialect: 'mysql',
host: '127.0.0.1',
port: 3306,
database: 'egg-sequelize-doc-default',
};
完成上面的配置之后,一个使用 sequelize 的项目就初始化完成了。egg-sequelize 和 sequelize 还支持更多的配置项,可以在他们的文档中找到。
(5)编写代码
现在终于可以开始编写代码实现业务逻辑了,首先我们来在 app/model/ 目录下编写 user 这个 Model:
'use strict';
module.exports = app => {
const { STRING, INTEGER, DATE } = app.Sequelize;
const User = app.model.define('user', {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
name: STRING(30),
age: INTEGER,
created_at: DATE,
updated_at: DATE,
});
return User;
};
这个 Model 就可以在 Controller 和 Service 中通过 app.model.User 或者 ctx.model.User 访问到了,例如我们编写 app/controller/users.js:
// app/controller/users.js
const Controller = require('egg').Controller;
function toInt(str) {
if (typeof str === 'number') return str;
if (!str) return str;
return parseInt(str, 10) || 0;
}
class UserController extends Controller {
async index() {
const ctx = this.ctx;
const query = { limit: toInt(ctx.query.limit), offset: toInt(ctx.query.offset) };
ctx.body = await ctx.model.User.findAll(query);
}
async show() {
const ctx = this.ctx;
ctx.body = await ctx.model.User.findByPk(toInt(ctx.params.id));
}
async create() {
const ctx = this.ctx;
const { name, age } = ctx.request.body;
const user = await ctx.model.User.create({ name, age });
ctx.status = 201;
ctx.body = user;
}
async update() {
const ctx = this.ctx;
const id = toInt(ctx.params.id);
const user = await ctx.model.User.findByPk(id);
if (!user) {
ctx.status = 404;
return;
}
const { name, age } = ctx.request.body;
await user.update({ name, age });
ctx.body = user;
}
async destroy() {
const ctx = this.ctx;
const id = toInt(ctx.params.id);
const user = await ctx.model.User.findByPk(id);
if (!user) {
ctx.status = 404;
return;
}
await user.destroy();
ctx.status = 200;
}
}
module.exports = UserController;
最后我们将这个 controller 挂载到路由上:
// app/router.js
module.exports = app => {
const { router, controller } = app;
router.resources('users', '/users', controller.users);
};
针对 users 表的 CURD 操作的接口就开发完了。
踩坑指南:
1.自动将表名称变为复数。
我创建的demo里的user表,自动被加上了s,变成了users。
解决方案(以下方法2选1 即可):
- 在定义model的时候,设置禁止转换为复数
const { STRING, INTEGER, DATE } = app.Sequelize;
const User = app.model.define('user', {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
real_name: STRING(10),
emp_id: INTEGER,
emp_name: STRING(6),
created_at: DATE,
updated_at: DATE,
},{
// 禁止修改表名,默认情况下,sequelize将自动将所有传递的模型名称(define的第一个参数)转换为复数
// 但是为了安全着想,复数的转换可能会发生变化,所以禁止该行为
freezeTableName: true
});
- 在配置文件里设置禁止转换为复数
// app/config/config.default.js
config.sequelize = {
"username": "root",
"password": null,
"database": "egg-sequelize-doc-default",
"host": "127.0.0.1",
"dialect": "mysql"
define: {
freezeTableName: true,//禁止转换为复数
},
};
2、直接将下划线转为驼峰。
因created_at会被转变成 createdAt故报错。
解决方案:在配置中设置不转为驼峰
// app/config/config.default.js
config.sequelize = {
"username": "root",
"password": null,
"database": "egg-sequelize-doc-default",
"host": "127.0.0.1",
"dialect": "mysql"
define: {
underscored: true,//禁止转换为驼峰
},
};
3、时间存储问题 mysql保存时会自动保存为UTC格式,可以在config中配置:
exports.sequelize = {
dialect: 'mysql',
....
timezone: '+08:00' // 保存为本地时区
}
但是egg-sequelize在读取时间时,还是会返回UTC格式,还需要改一下配置,添加:
exports.sequelize = {
dialect: 'mysql',
....
timezone: '+08:00' ,// 保存为本地时区
dialectOptions: {
dateStrings: true,
typeCast(field, next) {
// for reading from database
if (field.type === "DATETIME") {
return field.string();
}
return next();
}
}
}
4、 created_at 和 updated_at 字段 创建数据库表的时候,需要有这两个字段。
module.exports = app => {
const { STRING, INTEGER, DATE } = app.Sequelize;
const User = app.model.define('user', {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
real_name: STRING(10),
emp_id: INTEGER,
emp_name: STRING(6),
created_at: DATE,
updated_at: DATE,
});
return User;
};