前言

sequelize是什么? sequelize是基于NodeJs的ORM框架,它适用于不同的数据库,如:Postgres、MySQL、SQLite、MariaDB,我们可以通过sequelize对数据库进行一系列的操作。通常我用它与MySQL一起使用。该文是我在使用sequelize做完项目后对sequelize的系统整理。

准备工作

一、创建数据库和表,方便学习过程中书写示例代码

创建数据库 lesson

CREATE DATABASE IF NOT EXISTS lesson DEFAULT CHARSET utf8 COLLATE utf8_general_ci;

创建商品表 goods(示例使用,字段从简)

CREATE TABLE IF NOT EXISTS goods(

id INT(20) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '商品id',

name VARCHAR(64) NOT NULL COMMENT '商品名称',

title VARCHAR(200) NOT NULL COMMENT '商品标题',

descript TEXT COMMENT '商品描述',

num BIGINT UNSIGNED NOT NULL COMMENT '商品库存',

cateid INT(10) UNSIGNED NOT NULL COMMENT '分类id',

price DECIMAL(10,2) NOT NULL DEFAULT '0.00' COMMENT '商品价格',

create_time DATE COMMENT '创建时间',

update_time DATE COMMENT '修改时间'

)ENGINE=InnoDB;

创建分类表 categorys (示例使用,字段从简)

CREATE TABLE IF NOT EXISTS categorys(

id INT(20) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '分类id',

name VARCHAR(64) NOT NULL COMMENT '分类名称',

create_time DATE COMMENT '创建时间',

update_time DATE COMMENT '修改时间'

)ENGINE=InnoDB;

二、使用koa框架起一个服务

要学习使用sequelize,我们要先用node搭建基础服务,暴露接口方便测试,直观的看到代码效果。

引入包

在使用sequelize之前,我们需要引入两个包:sequelize、mysql2

npm install --save sequelize mysql2

连接数据库

要连接数据库,您必须new一个Sequelize的实例,给Sequelize构造函数传递参数完成连接。

const DB = new Sequelize(database,username,password,{

host:'',

dialect:''

})

database:要连接的数据库name

username:登录数据库时的用户名

password:登录数据库时的密码

options:选项配置参数,为一个对象,内含许多配置属性,如:

host:数据库主机

port:数据库端口号

dialect:指定要连接哪种类新的数据库,如:mysql、postgres等

define:为模型定义默认选项

timezone:时区

让我们先快速开始一个示例,从示例中学习需要注意的点 (请始终记住 我们使用的时准备阶段创建的数据库和表)

const {Sequelize,Model} = require('sequelize');

# 连接数据库

const connect = new Sequelize('lesson','root','abc123456',{

host:'localhost',

port:3306,

dialect:'mysql'

})

# 创建模型

class Category extends Model{}

Category.init({

name:Sequelize.STRING

},{

sequelize:connect,

tableName:'categorys'

})

# 新增一点数据

Category.create({name:'房产'})

当我们运行代码新增数据时,会发现数据没有添加成功且控制台报错。

为什么会出现这个问题呢? 这是因为Sequelize为了方便开发者,它会自动帮开发者添加上创建时间和更新时间,但是它给这两个时间规定了默认字段为createdAt和updatedAt,如果不做任何配置,我们创建数据库时创建时间和修改时间字段必须与它默认规定的相同。

与这两个字段相关联的有一个timestamp配置属性,这个属性可以启用或不启用Sequelize为开发者自动添加时间,默认为true。

对上面代码做一点点更改,如下:

# 连接数据库

const connect = new Sequelize('lesson','root','abc123456',{

host:'localhost',

port:3306,

dialect:'mysql',

+ define:{

+ timestamp:false

+ }

})

在实例化Sequelize时,加上define参数配置,可以作用于全局。 我们如上配置全局timestamp为false,即表示关闭自动添加时间,再次运行代码 我们会发现数据库添加了一条数据。

解决了上面添加数据失败的问题,但是没有创建时间,这显然不是我们所希望的。 我们再对代码做一些改动,添加上create_time字段如下:

# 创建模型

class Category extends Model{}

Category.init({

name:Sequelize.STRING,

+ update_time:{

+ type:Sequelize.DATE

+ }

},{

sequelize:connect,

tableName:'categorys'

})

# 新增一点数据

+ const create_time = new Date().getTime();

Category.create({name:'房产',create_time:create_time})

这时再打开数据库,我们可以看到有一条具有创建时间的数据已经被添加上去了

做到这里,我们知道了,不用Sequelize自动添加时间的方式,我们可以自己手动编码添加,而且数据库的时间字段可以是任意合法的字符。

当然,我们开启了timestamp,数据库的时间字段也可以是任意合法的字符。 这时候需要我们配置字段别名,这是很简单的,只需要添加两行代码就可以了,如下:

# 连接数据库

const connect = new Sequelize('lesson','root','abc123456',{

host:'localhost',

port:3306,

dialect:'mysql',

+ define:{

+ timestamp:true,

+ createdAt:'create_time',

+ updatedAt:'update_time'

+ }

})

上述篇幅,我们已经知道如何连接数据库和向数据库中添加数据,但是有些业务场景,不仅仅只是将我们在输入框中的数据原样插入到数据库中,可能会对输入的数据做一些改动,如用户注册时,密码需要加密然后再插入到数据库中。

需要实现这个需求,我们需要学习Sequelize的Setters、Getters和Virtuals

Setters: setter是为模型中字段的set()函数,它接收字段的值。它作用在数据的添加阶段,在set()函数中,我们可以获取字段的值并对原始值做一系列的变化,然后再设置最终值。

Getters: getter是为模型中字段的get()函数,它作用在数据的获取阶段,在get()函数中,我们可以先对返回值做一系列的操作,再返回最终值。

Virtuals: virtuals是虚拟字段,它不存在与数据库中。开发者可以使用它将两个字段拼接返回。

接下来我们来看看实际使用的栗子,代码如下:

Category.init({

name:{

type:Sequelize.STRING,

set(val){

const newVal = val + 'sb';// 所有添加的数据 name后都加上sb字符

this.setDataValue('name',newVal);

},

get() {

const rawValue = this.getDataValue('name');//获取字段值

return rawValue ? rawValue.toUpperCase() : null;//将字段值的字母转换成大写输出

}

},

vitName:{// 这是一个虚拟字段

type:Sequelize.VIRTUAL,

get(){

return `${this.name}`

}

}

},{

sequelize:connect,

tableName:'categorys'

})

到现在,我们已经学习了Sequelize很多的知识点了,接下来我们继续学习Sequelize的查询、修改、删除等方法。 在学习之前 我们还是先将数据库的数据维护一份正式一点的数据。

分别是分类表和商品表 如下图:

Sequelize为开发者提供了查找方法,默认情况下,所有查找器方法的结果都是模型类的实例,而不是简单的javascript对象。这意味着在数据库返回结果后,Sequelize会自动将所有内容打包到适当的实例对象中。在某些情况下,当结果太多时,这种包装可能效率低下,可以通过{raw:true}选项配置禁用。

查询选择器:

findAll:它生成一条标准的SELECT查询语句,在不受到条件语句限制的情况下从表中检索所有数据。

findByPk:根据提供的主键,从表中检索处一条数据。

findOne:如果不提供查询选项的话,它会检索到表中第一条数据。

count:检索数据库中所有数据,得到数据总数。

findAndCountAll:可以获得数据总量和数据列表。这在做分页数据时时非常方便的。

现在我们来查询表数据,实现一些需求。

所有商品:

router.get('/pro/list',async (ctx,next) => {

const result = await Product.findAll();

ctx.body = {

msg:result

}

})

得到的结果为:

{

"msg": [

{

"id": 2,

"name": "工装七分裤",

"title": "优衣库 男装 工装七分裤(卷边) 425146 UNIQLO ",

"descript": "优衣库 男装 工装七分裤(卷边) 425146 UNIQLO 优衣库 男装 工装七分裤(卷边) 425146 UNIQLO ",

"num": 158,

"cateid": 2,

"price": "149.00",

"create_time": "2020-07-25",

"update_time": "2020-07-25"

},

{

"id": 3,

"name": "花花公子旗舰短袖t恤",

"title": "花花公子旗舰短袖t恤男2020新款夏季潮牌宽松男士半袖潮流打底衫T ",

"descript": "花花公子旗舰短袖t恤男2020新款夏季潮牌宽松男士半袖潮流打底衫T 花花公子旗舰短袖t恤男2020新款夏季潮牌宽松男士半袖潮流打底衫T ",

"num": 3000,

"cateid": 2,

"price": "269.00",

"create_time": "2020-07-25",

"update_time": "2020-07-25"

},

{

"id": 4,

"name": "华为nova",

"title": "Huawei/华为 nova6 SE超级快充4800万AI四摄大运存nova6se 华为手机华为官方旗舰店 ",

"descript": "Huawei/华为 nova6 SE超级快充4800万AI四摄大运存nova6se 华为手机华为官方旗舰Huawei/华为 nova6 SE超级快充4800万AI四摄大运存nova6se 华为手机华为官方旗舰店",

"num": 2500,

"cateid": 3,

"price": "1999.00",

"create_time": "2020-07-25",

"update_time": "2020-07-25"

},

{

"id": 5,

"name": "荣耀30",

"title": "华为旗下荣耀30新品5G手机50倍超稳远摄麒麟985芯片全新智能手机正品官方旗舰店",

"descript": "华为旗下荣耀30新品5G手机50倍超稳远摄麒麟985芯片全新智能手机正品官方旗舰店华为旗下荣耀30新品5G手机50倍超稳远摄麒麟985芯片全新智能手机正品官方旗舰店",

"num": 3512,

"cateid": 3,

"price": "3299.00",

"create_time": "2020-07-25",

"update_time": "2020-07-25"

},

{

"id": 6,

"name": "美的变频空调",

"title": "美的i青春大1.5匹空调智能挂机冷暖壁挂式官方旗舰店",

"descript": "美的i青春大1.5匹空调智能挂机冷暖壁挂式官方旗舰店美的i青春大1.5匹空调智能挂机冷暖壁挂式官方旗舰店",

"num": 4215,

"cateid": 4,

"price": "2999.00",

"create_time": "2020-07-25",

"update_time": "2020-07-25"

},

{

"id": 7,

"name": "格力Gree",

"title": "Gree/格力 KFR-35GW 大1.5匹空调挂机智能变频冷暖一级壁挂式品悦",

"descript": "Gree/格力 KFR-35GW 大1.5匹空调挂机智能变频冷暖一级壁挂式品悦Gree/格力 KFR-35GW 大1.5匹空调挂机智能变频冷暖一级壁挂式品悦",

"num": 4215,

"cateid": 4,

"price": "4199.00",

"create_time": "2020-07-25",

"update_time": "2020-07-25"

},

{

"id": 8,

"name": "郁香菲2020夏季新品",

"title": "郁香菲2020夏季新品 荷叶边两穿收腰长款连衣裙纯色垂感飘逸长裙 ",

"descript": "郁香菲2020夏季新品 荷叶边两穿收腰长款连衣裙纯色垂感飘逸长裙 郁香菲2020夏季新品 荷叶边两穿收腰长款连衣裙纯色垂感飘逸长裙 ",

"num": 4215,

"cateid": 5,

"price": "699.00",

"create_time": "2020-07-25",

"update_time": "2020-07-25"

},

{

"id": 9,

"name": "美背文胸",

"title": "运动内衣女无钢圈聚拢冰丝无痕背心式胸罩夏季薄款调整型美背文胸 ",

"descript": "运动内衣女无钢圈聚拢冰丝无痕背心式胸罩夏季薄款调整型美背文胸 运动内衣女无钢圈聚拢冰丝无痕背心式胸罩夏季薄款调整型美背文胸 ",

"num": 10000,

"cateid": 5,

"price": "99.00",

"create_time": "2020-07-25",

"update_time": "2020-07-25"

}

]

}

条件查询

查询

router.get('/pro/list',async (ctx,next) => {

const result = await Product.findAll({

where:{

id:4

}

});

ctx.body = {

msg:result

}

})

结果:

{

"msg": [

{

"id": 4,

"name": "华为nova",

"title": "Huawei/华为 nova6 SE超级快充4800万AI四摄大运存nova6se 华为手机华为官方旗舰店 ",

"descript": "Huawei/华为 nova6 SE超级快充4800万AI四摄大运存nova6se 华为手机华为官方旗舰Huawei/华为 nova6 SE超级快充4800万AI四摄大运存nova6se 华为手机华为官方旗舰店",

"num": 2500,

"cateid": 3,

"price": "1999.00",

"create_time": "2020-07-25",

"update_time": "2020-07-25"

}

]

}

查询

router.get('/pro/list',async (ctx,next) => {

const result = await Product.findOne({

where:{

id:4

}

});

ctx.body = {

msg:result

}

})

# 等同于

router.get('/pro/list',async (ctx,next) => {

const result = await Product.findByPk(4);

ctx.body = {

msg:result

}

})

结果一样,都是

{

"msg": {

"id": 4,

"name": "华为nova",

"title": "Huawei/华为 nova6 SE超级快充4800万AI四摄大运存nova6se 华为手机华为官方旗舰店 ",

"descript": "Huawei/华为 nova6 SE超级快充4800万AI四摄大运存nova6se 华为手机华为官方旗舰Huawei/华为 nova6 SE超级快充4800万AI四摄大运存nova6se 华为手机华为官方旗舰店",

"num": 2500,

"cateid": 3,

"price": "1999.00",

"create_time": "2020-07-25",

"update_time": "2020-07-25"

}

}

注意:findAll和findOne、findByPk方法得到的结果是不同的,findAll得到的结果是数组包含着数据项,而findOne、findByPk得到的结果就是一条数据

分页查询

我们在项目中经常会需要分页查询,一次性查询所有的数据,无论是服务器还是前端页面显示都是不友好的。Sequelize为开发者提供了分页机制,我们只需配置offset和limit两个属性就可以实现分页。

offset:偏移量,以0开始做偏移

limit:限制条数

值得我们注意的是offset是以0开始做偏移的,通常前端分页会传递两个参数:pageCurrent和pageSize。 pageCurrent通常是以1开始的。所以后端接收到pageCurrent后需要减1传递给Sequelize做偏移。

router.get('/pro/list',async (ctx,next) => {

const { pageCurrent,pageSize } = ctx.request.body;

let limit = pageSize ? pageSize : limit;

let offset = pageCurrent ? (pageCurrent - 1)*limit : offset;

const result = await Product.findAll({

offset,

limit

});

ctx.body = {

msg:result

}

})

指定字段

router.get('/pro/list',async (ctx,next) => {

const result = await Product.findOne({

attributes:['name','price']

});

ctx.body = {

msg:result

}

})

结果

{

"msg": {

"name": "工装七分裤",

"price": "149.00"

}

}

排除字段

router.get('/pro/list',async (ctx,next) => {

const result = await Product.findOne({

attributes:{

exclude:['descript']

}

});

ctx.body = {

msg:result

}

})

结果

{

"msg": {

"id": 2,

"name": "工装七分裤",

"title": "优衣库 男装 工装七分裤(卷边) 425146 UNIQLO ",

"num": 158,

"cateid": 2,

"price": "149.00",

"create_time": "2020-07-25",

"update_time": "2020-07-25"

}

}

排序查询

配置order选项,order是一个数组,字段名和排序方式。 desc(降序),asc(升序)

router.get('/pro/list',async (ctx,next) => {

const result = await Product.findAll({

order:[

['id','desc']

]

});

ctx.body = {

msg:result

}

})

关联查询

sequelize提供了四种类型的关联关系

hasOne关联:与目标建立一对一关联关系,外键存在于目标模型中

belongsTo关联:与目标建立一对一关联关系,外键存在于源模型中

hasMany:与目标建立一对多关联关系,外键存在于目标模型中

belongsToMany:与目标建立多对多关联关系,外键存在于源模型中

# 外键存在于源模型中

Product.belongsTo(Category,{

foreignKey:'cateid',

targetKey:'id'

})

# 外键存在于目标模型中

Product.hasOne(Category,{

as:'cate',

foreignKey:'id',

targetKey:'cateid'

})

上面两个代码示例, Product模型是源模型,Category模型是目标模型。cateid是Product中定义的字段列,可以看到使用belongsTo时外键foreignKey的值是cateid 使用hasOne时外键foreignKey的值是id ,这个id是Category中的主键id。

示例代码:

Product.hasOne(Category,{

foreignKey:'id',

targetKey:'cateid'

})

router.get('/pro/list',async (ctx,next) => {

const result = await Product.findOne({

include:{

model:Category

}

});

ctx.body = {

msg:result

}

})

得到结果:

{

"msg": {

"id": 2,

"name": "工装七分裤",

"title": "优衣库 男装 工装七分裤(卷边) 425146 UNIQLO ",

"descript": "优衣库 男装 工装七分裤(卷边) 425146 UNIQLO 优衣库 男装 工装七分裤(卷边) 425146 UNIQLO ",

"num": 158,

"cateid": 2,

"price": "149.00",

"create_time": "2020-07-25",

"update_time": "2020-07-25",

"Category": {

"id": 2,

"name": "男装",

"create_time": "2020-07-25",

"update_time": "2020-07-25"

}

}

}

商品信息中就有了该商品所属分类的信息,可以看到返回的商品信息字段是Category即是以定义的类名Category为字段,我们可以更改它。

Product.hasOne(Category,{

+ as:'cate',

foreignKey:'id',

targetKey:'cateid'

})

router.get('/pro/list',async (ctx,next) => {

const result = await Product.findOne({

include:{

model:Category,

+ as:'cate'

}

});

ctx.body = {

msg:result

}

})

这样分类信息的字段就跟更改成了cate

Category.update(param,option)

param:修改的参数集合,Object

option:配置选项

router.post('/edit',async (ctx,next) => {

await Category.update({

name:'男装内裤'

},{

where:{

id:2

}

})

})

上面代码 修改id等于2的那条数据,将name字段的值更改为'男装内裤'。

Category.destroy(option)

Category.destroy({

where:{

id:2

}

})

mysql 主键 uniqo_项目总结,彻底掌握NodeJS中如何使用Sequelize相关推荐

  1. mysql主键干嘛的_数据库表中的主键有什么作用?

    展开全部 数据库主键 主键:表中经常有一个列或多列的组合,其值能唯一地标识表中的每一行.这样e69da5e6ba9062616964757a686964616f31333365643534的一列或多列 ...

  2. mysql 主键 uniqo_优衣库某处SQL注入可导致移动平台被劫持

    漏洞概要 缺陷编号:WooYun-2014-073739 漏洞标题:优衣库某处SQL注入可导致移动平台被劫持 相关厂商:优衣库 漏洞作者:winsyk 提交时间:2014-08-25 10:08 公开 ...

  3. mysql主键long_MySQL主键设计

    [TOC] 在项目过程中遇到一个看似极为基础的问题,但是在深入思考后还是引出了不少问题,觉得有必要把这一学习过程进行记录. MySQL主键设计原则 MySQL主键应当是对用户没有意义的. MySQL主 ...

  4. MySQL主键设计盘点

    文章目录 主键定义 主键设计和应用原则 主键生成策略 自增ID UUID 自建的id生成器 Twitter的snowflake算法 最近在项目中用了UUID的方式生成主键,一开始只是想把这种UUID的 ...

  5. mysql主键自增长空缺_Mysql 主键自增长auto_increment问题分析

    本节内容: Mysql 主键自增长 在mysql数据库中,主键由auto_increment实现自增长,若自定义函数来表示auto_increment的话可以如下: 复制代码 代码示例: create ...

  6. Oracle与Mysql主键、索引及分页的区别小结

    Oracle与Mysql主键.索引及分页的区别,学习oracle的朋友可以参考下 区别: 1.主键,Oracle不可以实现自增,mysql可以实现自增. oracle新建序列,SEQ_USER_Id. ...

  7. MySQL主键学习总结

    浅谈MySQL主键 主键没有着明确的概念定义,其是索引的一种,并且是唯一性索引的一种,且必须定义为"PRIMARY KEY",主键不能重复,一个表只能有一个主键. 1.声明主键的方 ...

  8. MySQL主键(PRIMARY KEY)

    "主键(PRIMARY KEY)"的完整称呼是"主键约束".MySQL 主键约束是一个列或者列的组合,其值能唯一地标识表中的每一行.这样的一列或多列称为表的主键 ...

  9. 2、MySQL主键(PRIMARY KEY)

    主键(PRIMARY KEY)的完整称呼是"主键约束",是 MySQL 中使用最为频繁的约束.一般情况下,为了便于 DBMS 更快的查找到表中的记录,都会在表中设置一个主键. 主键 ...

最新文章

  1. js轮播图片小圆点变化_原生js实现轮播图(两种方法)
  2. mongodb存入mysql_关于mongodb转存MySQL
  3. 项目常用的PHP代码
  4. java输入流读取几行文本_Java基础笔记Day_16
  5. leetcode904. 水果成篮(滑动窗口)
  6. lstm网络_LSTM(长短期记忆网络)
  7. ubuntu命令行相关命令使用心得
  8. 计算机绘图 电子教案,机械制图与计算机绘图电子教案大全.doc
  9. button 和 input 的submit ,reset的区别
  10. 2020.1.8学习
  11. c语言地铁系统设计,城市地铁报站系统设计.doc
  12. 小米手机5s简单刷成开发版获得ROOT权限的方法
  13. chrome扩展——bilibili视频封面获取器
  14. 计算机运用基础2020四川传媒学院考题,2020年计算机基础考试题EY[含答案](15页)-原创力文档...
  15. 通过简单的强化学习实现井字棋(Tic-Tac-Toe)
  16. 电商系统-优惠券叠加规则、优惠分摊介绍(三)
  17. swfobject.js 的用法
  18. 单片机实现PT2262解码示例代码
  19. nova-week2
  20. 知识型员工的普遍特点(摘录)

热门文章

  1. python爬虫原理-python爬虫从入门到放弃(二)之爬虫的原理
  2. python课程多少钱一节课-日照少儿python编程一节课多少钱
  3. 基于arcgis的python脚本编程视频-面向ArcGIS的Python脚本编程 PDF 高清版
  4. 用python开发的网站多吗-django可以开发大型网站吗
  5. python中文读音ndarray-numpy中的ndarray方法和属性详解
  6. python编程基础教程-史上最全Python编程基础入门教程
  7. python基础教程第三版豆瓣-Python爬虫入门教程:豆瓣读书练手爬虫
  8. python3菜鸟教程中文-Python3 字符串
  9. 成都理工大学计算机报告,[2017年整理]成都理工大学通信工程计算机网络综合课程设计报告.doc...
  10. java 环境变量 locale,修改locale把语言环境变量改为英文