Node.JS使用Sequelize操作MySQL的示例代码


Posted in Javascript onOctober 09, 2017

Node.JS提供了操作数据库的基础接口,我们可以通过mysql模块的query方法进行操作,但是需要编写SQL语句,对于SQL语句并不精通的人来说有一定的难度,而且在代码中保留SQL语句也有一定的危险性。为了方便进行数据库操作,ORM框架应运而生,Sequelize正是这样的模块。

安装Sequelize

首先,使用cd命令将终端控制台定位到项目的根目录,然后使用npm安装:

npm install sequelize --save

安装mysql2

由于sequelize依赖于mysql2所以也需要安装mysql2:

npm install mysql2 --save

编写配置

在项目根目录新建个“configs”文件夹,在文件夹中新建一个名为“mysql-config.js”的文件,代码如下:

var config = {
  dbname: 'testdb',
  uname: 'root',
  upwd: 'root',
  host: 'localhost',
  port: 3306,
  dialect: 'mysql',
  pool: {
    max: 5,
    min: 0,
    idle: 10000
  }
};

module.exports = config;

配置说明

  • dbname: 数据库名称
  • uname: 数据库登录名
  • upwd: 数据库登录密码
  • host: 数据库主机
  • port: 数据库端口,mysql默认是3306
  • dialect: 数据库类型,这里是mysql
  • pool: 连接池配置

【具体配置详见MySQL相关的博客】

对sequelize进行简单封装

在项目根目录新建“data”文件夹,在改文件夹中新建“db.js”文件。在db.js中添加以下代码。

首先,创建sequelize实例:

// 引入模块
const Sequelize = require('sequelize');
// 读取配置
const mysqlConfig = require('../configs/mysql-config');

// 根据配置实例化seq
var seq = new Sequelize(mysqlConfig.dbname, mysqlConfig.uname, mysqlConfig.upwd, {
  host: mysqlConfig.host,
  dialect: mysqlConfig.dialect,
  pool: mysqlConfig.pool
});

定义一个defineModel函数用于定义数据模型:

/**
 * 定义数据模型
 * 
 * @param {any} name 模型名称【数据库表名】
 * @param {any} attributes 数据字段集合
 * @returns 数据模型对象
 */
function defineModel (name, attributes) {
  var attrs = {};

  for (let key in attributes) {
    let value = attributes[key];
    if (typeof value === 'object' && value['type']) {
      value.allowNull = value.allowNull || false;
      attrs[key] = value;
    } else {
      attrs[key] = {
        type: value,
        allowNull: false
      };
    }
  }

  // 附加公共字段
  // attrs.id = {
  //   type: ID_TYPE,
  //   primaryKey: true
  // };
  attrs.createAt = {
    type: Sequelize.BIGINT,
    allowNull: false
  };
  attrs.updateAt = {
    type: Sequelize.BIGINT,
    allowNull: false
  };
  attrs.version = {
    type: Sequelize.BIGINT,
    allowNull: false
  };
  // 状态:0表示有效,1表示无效,2表示已删除,默认为0.
  attrs.status = {
    type: Sequelize.INTEGER,
    allowNull: false
  };
  
   // 调用seq的方法定义模型并返回
  return seq.define(name, attrs, {
    tableName: name,
    timestamps: false,
    hooks: {
      beforeValidate: function (obj) {
        let now = Date.now();
        if (obj.isNewRecord) {
          obj.createAt = now;
          obj.updateAt = now;
          obj.version = 0;
        } else {
          obj.updateAt = now;
          ++obj.version;
        }
      }
    }
  });
}

在这里我们可以对模型定义做一些修改,比如添加id、createAt、updateAt、version和status字段等。这样,通过这个函数定义的模型都会带这几个字段,通常一个数据库表都应该包含这些字段。

sequelize默认会为模型添加id字段,自增,主键。所以在这里可以不用关心该字段的定义。

在调用seq.define()方法的时候,设置了“timestamps”为false,当timestamps为true时,默认会为模型添加createAt和updateAt两个字段,数据类型为Sequelize.DATE,这里我们自己定义为Sequelize.BIGINT用于存储时间戳。

同时,设置tableName和模型的名称一致,这样符合我们的惯性思维。

最后,db.js模块导出defineModel函数:

exports.defineModel = defineModel;

定义模型

在data目录下新建“model”文件夹,并在model文件夹中添加“Notices.js”。在Notices中,先引入需要的模块:

var db = require('../db');
var seq = require('sequelize');

然后定义数据模型对象:

var Model = db.defineModel('Notices', {
  content: seq.TEXT,
  title: seq.STRING(30),
  startDate: seq.BIGINT,
  expireDate: seq.BIGINT,
  gmId: seq.INTEGER(10),
});

// 导出模型对象
module.exports = Model;

引入的db模块就是前面对sequelize的封装,然后通过defineModel()函数定义模型,添加公共字段。

在这里引入sequelize模块主要是为了定义模型的时候指定数据类型。

同步数据结构到数据库

当模型定义后,需要在数据库中建立对应的数据表,这时候需要做结构的同步,可以使用以下方法进行同步:

Model.sync();

如果数据库中已经存在该模型对应的表,则不会进行同步操作,如果想要强制进行数据结构的同步,可以通过force参数指定:

Model.sync({force: true});

使用模型

在Notices.js文件中可以直接使用Model对象进行操作,如果是外部文件,需要先引入Notices模块

var Notices = require('../data/model/Notices');

添加数据

通过数据模型对象的create方法可以添加一条数据,方法的返回值是一个Promise对象,所以可以直接调用Promise对象的then方法进行后续操作。

Notices.create({
  content: '我是公告内容。',
  title: '系统公告的标题',
  gmId: '10086',
  status: 0,
  expireDate: 1527396599123,
  startDate: Date.now()
}).then((data) => {
  res.json({ code: 0, msg: '公告发布成功', result: data });
});

then方法的参数是一个function对象,该function对象有一个data参数,这个data参数就是前面create方法操作的数据对象,可以从data里面获得数据在数据库中的id是什么。

通过await和async来实现同步编程效果

通过then的方式很像是嵌套function的回调式异步编程,有些有不喜欢嵌套function的人可以采用await来实现同步编程的效果,更多关于await的用法这里不讨论。

(async () => {
  var data = await Notices.create({
    content: '我是公告内容。',
    title: '系统公告的标题',
    gmId: '10086',
    status: 0,
    expireDate: 1527396599123,
    startDate: Date.now()
  });

  res.json({ code: 0, msg: '公告发布成功', result: data });
})();

await修饰的函数调用必须写在async修改的函数里面,否则会报错,所以这里在最外层包了一个即时函数。

关于即时函数的概念可以参考《JavaScript面向对象编程指南》这本书,里面说的挺详细的。简单说就是定义后立刻调用的一个函数。

修改数据

使用模型对象的update方法可以修改数据:

Notices.update({
  status: 2
}, {
  where: {id: 100}
});

updata(values, opts)方法的第一个参数是要修改的数据集合,字段名称和数据表对应。第二个参数是相关的一些操作参数,where用于限制修改的数据的条件,和SQL语句的where作用一样。

上面的效果是修改id为100的数据的status字段的值为2。

查询数据

通过数据模型对象的find相关的方法可以实现查询效果:

查询所有数据

Notices.findAll();

改方法会返回Notices表中所有的数据,返回值依然是一个Promise对象。

条件查询

Notices.findAll({order: [['createAt', 'DESC']], limit: 10, where: {'status': 0}});
  • order字段用于指定排序规则,这里指定以createAt字段做降序排序。
  • limit字段用于指定查询的数据量,这里表示返回前10条数据。
  • where字段用于指定条件查询,这里表示查询status为0的数据。

删除数据

通过数据模型对象的destroy方法可以销毁一条数据,具体用法和查询、修改等类似。

但是通常我们做删除操作的时候并不是真的将数据从数据库中抹除,而是通过数据的状态字段去标识,方便后续维护。所以每个表通常都会定义一个status字段。

复杂的where条件

在sequelize中,还存在一个Op对象,用于处理复杂的条件操作。

[案例一]

var seq = require('sequelize');
var Op = seq.Op;

// 其它代码... 

Model.update({
  status: 2,
  gmId: 10086
}, {
  where: {
    id: {
      [Op.in]: [1, 4, 2, 8, 13, 20]
    }
  }
});

上面这段代码表示修改status的值为2,修改gmId的值为10086。修改的条件的,数据的id字段必须是在[1, 4, 2, 8, 13, 20]这个数组中的数据。

[案例二]

var date = Date.now();

Model.findAll({
  where: {
    status: 0, 
    sendDate: {[Op.lte]: date}, 
    expireDate: {[Op.gte]: date},
    [Op.or]: [
      {to: 1000017},
      {to: 0}
    ]
  }
});

上面这段代码表示查询所有sendDate小于等于当前时间,并且expireDate大于等于当前时间,且status的值为0,并且to字段的值为1000017或者为0。

参考文档

以上也只是举了一部分例子进行简单说明而已,详细的可以查考这份文档,虽然是英文的,但是稍微花点时间应该多少是可以看懂的。

http://docs.sequelizejs.com/identifiers.html

【写在文末:ORM方便了数据库的操作,但是对于很多复杂的业务,它可能也并不能很好的解决,所以某些特定需求还是需要SQL来实现。】

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
IE与Firefox下javascript getyear年份的兼容性写法
Dec 20 Javascript
jquery实现marquee效果(文字或者图片的水平垂直滚动)
Jan 07 Javascript
Javascript 鼠标移动上去小三角形滑块缓慢跟随效果
Apr 26 Javascript
node.js中的fs.mkdirSync方法使用说明
Dec 17 Javascript
jQuery实现的可编辑表格完整实例
Jun 20 Javascript
javascript数组遍历的方法实例分析
Sep 13 Javascript
vue高德地图之玩转周边
Jun 16 Javascript
iscroll动态加载数据完美解决方法
Jul 18 Javascript
详解如何让InstantClick兼容MathJax、百度统计等
Sep 12 Javascript
JS删除数组里的某个元素方法
Feb 03 Javascript
vue实现的上传图片到数据库并显示到页面功能示例
Mar 17 Javascript
【js设计模式】SOLID五大设计原则
Mar 24 Javascript
基于zepto.js实现登录界面
Oct 09 #Javascript
浅谈在koa2中实现页面渲染的全局数据
Oct 09 #Javascript
jQuery实现html双向绑定功能示例
Oct 09 #jQuery
jqueryUI tab标签页代码分享
Oct 09 #jQuery
ES6学习教程之模板字符串详解
Oct 09 #Javascript
ES6学习教程之块级作用域详解
Oct 09 #Javascript
JavaScript实现短信倒计时60s
Oct 09 #Javascript
You might like
高分R级DC动画剧《哈莉·奎茵》第二季正式预告首发
2020/04/09 欧美动漫
Apache设置虚拟WEB
2006/10/09 PHP
zf框架的校验器InArray使用示例
2014/03/13 PHP
ThinkPHP路由详解
2015/07/27 PHP
ThinkPHP和UCenter接口冲突的解决方法
2016/07/25 PHP
PHP yield关键字功能与用法分析
2019/01/03 PHP
关于js获取radio和select的属性并控制的代码
2011/05/12 Javascript
JS两种定义方式的区别、内部原理
2013/11/21 Javascript
使用 stylelint检查CSS_StyleLint
2016/04/28 Javascript
js removeChild 方法深入理解
2016/08/16 Javascript
Vue概念及常见命令介绍(1)
2016/12/08 Javascript
canvas绘制多边形
2017/02/24 Javascript
canvas实现爱心和彩虹雨效果
2017/03/09 Javascript
详谈Angular 2+ 的表单(一)之模板驱动型表单
2017/04/25 Javascript
微信小程序开发之实现自定义Toast弹框
2017/06/08 Javascript
基于JavaScript实现飘落星星特效
2017/08/10 Javascript
详谈构造函数加括号与不加括号的区别
2017/10/26 Javascript
vue滚动固定顶部及修改样式的实例代码
2019/05/30 Javascript
微信小程序制作扭蛋机代码实例
2019/09/24 Javascript
JavaScript实现单图片上传并预览功能
2019/09/30 Javascript
js实现文字头像的生成代码
2020/03/07 Javascript
Python实现文件按照日期命名的方法
2015/07/09 Python
简单上手Python中装饰器的使用
2015/07/12 Python
Python中文件I/O高效操作处理的技巧分享
2017/02/04 Python
基于Python的Post请求数据爬取的方法详解
2019/06/14 Python
python SocketServer源码深入解读
2019/09/17 Python
使用Python开发个京东上抢口罩的小实例(仅作技术研究学习使用)
2020/03/10 Python
Python常驻任务实现接收外界参数代码解析
2020/07/21 Python
几款好用的python工具库(小结)
2020/10/20 Python
Python的logging模块基本用法
2020/12/24 Python
意大利专业化妆品品牌:KIKO MILANO
2017/02/01 全球购物
乐高官方旗舰店:LEGO积木玩具
2019/04/06 全球购物
2014年幼儿园教研工作总结
2014/12/04 职场文书
党员倡议书
2015/01/19 职场文书
读书笔记格式
2015/07/02 职场文书
如何利用map实现Nginx允许多个域名跨域
2021/03/31 Servers