最近开始接触数据库,如今广泛用的都是Mysql
数据库,简单的了解了一下sql
语句,没有太深刻的学习,而后就开始找相关的ORM
框架,而后锁定了Sequelize
,我的感受很强大,搜索了一些文档,可是很让人费解,讲的每一部分都是那么的官方,不太容易理解,记录一下学习路程。本文档以koa
+Sequelize
进行编码测试。javascript
准备工做
在尝试使用Sequelize
以前先确认是否安装了Mysql
数据库,安装node
,这里使用的Mysql 5.6
版本。前端
首先要建立一个项目执行命令以下:java
mkdir 文件夹名称 cd 文件夹名称 npm init -y // 直接略过全部问答,所有采用默认答案
在开始以前首先要安装相关依赖:node
// 安装 sequelize koa mysql2 npm install --save-dev sequelize koa mysql2
注意:这里是mysql2mysql
创建链接
建立main.js
文件,分别引入koa
和sequelize
创建与mqsql
数据库链接。在实例化Sequelize
时须要配置一些参数,第一个接收的参数时数据库的名称,第二个是用户名,第三个是密码,第四项是链接mysql
的相关配置。sql
const Koa = require("koa"); const Sequelize = require("sequelize"); const app = new Koa(); const mysqlConfig ={ host: 'localhost', // 接数据库的主机 port: '3306', // 接数据库的端口 protocol: 'tcp', // 链接数据库使用的协议 dialect: 'mysql', // 使用mysql pool: { max: 5, // 最大链接数量 min: 0, // 最小链接数量 idle: 10000 // 链接空置时间(毫秒),超时后将释放链接 }, retry: { // 设置自动查询时的重试标志 max: 3 // 设置重试次数 }, omitNull: false, // null 是否经过SQL语句查询 timezone: '+08:00' // 解决时差 - 默认存储时间存在8小时偏差 }; const sequelize = new Sequelize('aarontest', 'root', '123456',mysqlConfig ); app.listen(3000);
经过上述代码就已经与Mysql
创建了链接。这个地方没有什么能够讲的,按照上述进行配置就能够了。test
数据库不必定要存在不存在也是能够正常创建链接的。配置参数还有不少,这里只说了一些经常使用的,就很少赘述了。若是以为上述方法比较麻烦能够经过也提供了其余方法进行链接:数据库
const sequelize = new Sequelize('mysql://root:123456@localhost:3306/aarontest', { ...mysqlConfig });
这种链接方式与mongoose
链接方法差很少,以致于具体使用哪一种方式仍是要根据我的的编码习惯来决定。npm
创建model
sequelize
是经过define
方法创建模型的,Model
至关于数据库中的表,该对象不能经过构造函数实例化,而只能经过sequelize.define()
或sequelize.import()
方法建立。json
const AaronTest = sequelize.define('project', { title: Sequelize.STRING, description: Sequelize.TEXT })
经过上面的方法建立好model
以后,使用Navicat
(数据库可视化工具)仍然没法看到咱们所建立的表,尴尬。。。sequelize
提供了一个sync()
方法能够同步模型到数据库。使用该方法的时候必定要注意所链接的数据库必定要存在
不然会报错。后端
define
方法接收三个参数,第一个参数为表名称,第二个为所须要建立的数据库字段,第三个参数是相关表配置。
const AaronTest = sequelize.define('project', { title: Sequelize.STRING, description: Sequelize.TEXT }); AaronTest.sync();
这样model
所建立的字段就被同步到了数据库中,一样相对应的表也被建立好了,须要注意经过这种方式同步的表会在表名称后面添加一个s
做为复数。同步数据库是会默认添加两个字段createdAt
和updatedAt
有的时候可能不须要这两个字段。这个时候须要在第三个字段中添加timestamps
为false
默认为true
。
const AaronTest = sequelize.define('project', { title: Sequelize.STRING, description: Sequelize.TEXT },{ timestamps: false })
上面能够看出经过Sequelize.STRING
设置当前字段的类型,Sequelize
提供了不少数据类型供咱们进行使用:
类型 | 说明 |
---|---|
STRING | 将字段指定为变长字符串类型,默认长度为 255。Sequelize.STRING(64) |
CHAR | 将字段指定为定长字符串类型,默认长度为 255。Sequelize.CHAR(64) |
TEXT | 将字段指定为(无)有限长度的文本列。可用长度:tiny, medium, long,Sequelize.TEXT('tiny') |
INTEGER | 32位整型,可用属性:UNSIGNED,ZEROFILL,Sequelize.INTEGER('UNSIGNED') |
BOOLEAN | 小数,接受一个或两个参数表示精度,Sequelize.BOOLEAN() |
TIME | 指定为时间类型列,Sequelize.TIME() |
DATE | 指定为日期时间类型列,Sequelize.DATE() |
DATEONLY | 指定为日期类型列,Sequelize.DATEONLY() |
HSTORE | 指定为键/值类型列,仅Postgres适用,Sequelize.HSTORE() |
JSON | 指定为JSON字符串类型列,仅Postgres适用,Sequelize.JSON() |
JSONB | 指定为预处理的JSON数据列,仅Postgres适用,Sequelize.JSONB() |
NOW | 一个表示当前时间戳的默认值,Sequelize.NOW() |
UUID | UUID类型列,其默认值能够为UUIDV1或UUIDV4,Sequelize.UUID() |
ENUM | 枚举类型,Sequelize.ENUM() |
ARRAY | 数组类型,仅Postgres适用,Sequelize.ARRAY() |
设定model的时候在添加第三个参数能够对当前model
进行二次设置,以使数据库更增强壮,经常使用字段以下
当建立model
的时候可能须要有些附加属性,好比主键
,自增
,不能为null
,默认值等等,能够在建立model
的时候进行手动设置。
除了这些之外Sequelize
在定义model
的时候,还提供了一个validate
属性,能够为添加的字段进行校验处理:
字段 | 说明 | 值类型 |
---|---|---|
is | 存储值必须知足正则 | 正则 |
not | 除正则以外的值 | 布尔 |
isEmail | 是否为邮箱 | 布尔 |
isUrl | 检查Url格式 | 布尔 |
isIP | 检查 IPv4 或 IPv6 格式 | 布尔 |
isIPv4 | 检查 IPv4 | 布尔 |
isIPv6 | 检查 IPv6 | 布尔 |
isAlpha | 不能使用字母 | 布尔 |
isAlphanumeric | 只容许字母数字字符 | 布尔 |
isNumeric | 只能使用数字 | 布尔 |
isInt | 只能是整数 | 布尔 |
isFloat | 只能是浮点数 | 布尔 |
isDecimal | 检查数字 | 布尔 |
isLowercase | 检查小写字母 | 布尔 |
isUppercase | 检查大写字母 | 布尔 |
notNull | 不容许null | 布尔 |
isNull | 只能为null | 布尔 |
notEmpty | 不能空字符串 | 布尔 |
equals | 只能使用指定值 | 字符串 |
contains | 必须包含子字符串 | 字符串 |
notIn | 不能是数组中的任意一个值 | 数组 |
isIn | 只能是数组中的任意一个值 | 数组 |
notContains | 不能包含子字符串 | 字符串 |
len | 值的长度必在 2 和 10 之间 | 数组 |
isUUID | 只能是UUID | 数字 |
isDate | 只能是日期字符串 | 布尔 |
isAfter | 只能使用指定日期以后的时间 | 字符串 |
isBefore: | 只能使用指定日期以前的时间 | 字符串 |
max | 容许的最大值 | 数字 |
min | 容许的最小值 | 数字 |
isArray | 不能使用数组 | 布尔 |
isCreditCard | 检查是有效的信用卡 | 布尔 |
除了上面的校验方法之外还提供了自定义校验方法,使用isEven
去定义一个函数,其函数的第一个参数就是所存如的值:
const AaronTest = sequelize.define('project', { title: Sequelize.STRING, description: { type:Sequelize.TEXT, validate:{ isEven: function(value) { if(parseInt(value) % 2 != 0) { throw new Error('Only even values are allowed!') } } } } },{ timestamps: false })
上面说过使用sequelize.import()
也能够建立model
这个方法实际上是模型导入,经过文件导入模型定义。检查模型是否已经定义。被导入的模型会被缓存,因此屡次导入并不会重复加载,path表示要导入文件的路径,若是使用相对路径会自动转换为绝对路径。
const AaronTest = sequelize.import('../model/user.js');
user.js
module.exports = function(sequelize, DataTypes) { return sequelize.define("project", { name: DataTypes.STRING, description: DataTypes.TEXT }) }
CRUD
CRUD:是指在作计算处理时的增长(Create)、读取(Read)、更新(Update)和删除(Delete)几个单词的首字母简写。crud主要被用在描述软件系统中数据库或者持久层的基本操做功能。
建立
建立数据的方法有不少种,这里简单的介绍一些经常使用的:
第一种:
先建立数据实例,而后调用实例的save
方法,完成数据存储。
const Aaron = AaronTest.build({ 'title': `后端 | ${Math.random()}`, 'description': '技术部' }); Aaron.save().then((result) => { // 成功 console.log(result) }).catch((error) => { // 失败 console.log(error) })
第二种:
经过静态create
方法
const user = AaronTest.create({ 'title': `前端 | ${Math.random()}`, 'description': '网络部' }).then(function(result) { // 成功 console.log(result) }).catch(function(error) { // 失败 console.log(error) });
读取
经过findAll
方法读取数据。
AaronTest.findAll({ where: { description: '网络部' }, limit: 10, offset: 0 }).then(function(result) { // success console.log(result) }).catch(function(error) { // error console.log(error) });
经过上述方法建立的数据能够直接做为返回结果返回给前台,可是若是对查询到的结果进行数据操做时不行的,由于查询到的结果是sequelize
处理过的模型,若是想对其操做须要在参数中添加row:true
属性。
AaronTest.findAll({ where: { description: '网络部' }, limit: 10, // 查询多少条 offset: 0, // 查询开始位置 raw:true }).then(function(result) { // success console.log(result) }).catch(function(error) { // error console.log(error) });
添加row:true
返回的则是一个没有被包装过的数组了。在项目过程当中须要查询一下当前所查询的数据共有多少条返回给前端。
AaronTest.count({ where:{ description: '网络部' } }).then().then(function(result) { // success console.log(result) }).catch(function(error) { // error console.log(error) });
使用这种方法是确实能够查询到想要的结果,可是不管是先查询列表仍是先查询总数,都须要对数据库进行两次查询很繁琐。sequelize
提供了一个很方便的方法。
AaronTest.findAndCountAll({ where: { description: '网络部' }, limit: 10, offset: 0, raw:true, attributes:["id", "title"] // 须要查询出的字段 }).then(function(result) { // success console.log(result) }).catch(function(error) { // error console.log(error) });
经过上面的方法则能够查询到总数以及条件范围内的数据,一箭双雕。查询结果返回的是一个json
对象,其包括cont
和rows
两个属性,分别是总数和数据。很舒服有没有。
以上方式是查询列表,查询单条数据使用其余方法:
AaronTest.findOne({ where:{ id:6 }, raw:true, attributes:["id", "title"] }).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
更新
修改数据能够直接调用静态的update
方法,经过where
条件查询,对其搜索到的数据进行查询,并对查询到的数据进行更改。
AaronTest.update({ description: '前端部', title:`前端 | ${Math.random()}` },{ where:{ description: "网络部" } }).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
该方法修改全部查询的到的数据,返回结果为数组形式,数据只有一个值,也就是数组的第0
项,则是N
条数据修改为功。
删除
删除操做经过destroy
方法,一样也是经过where
条件查询,对所查询数据进行删除。
AaronTest.destroy({ where: { description: "UI部", } }).then(function(result) { console.log(result) }).catch(function(error) { console.log(error) });
当删除成功后,返回结果为Number
,删除多少条数据,若是没有删除则会返回0
。此方法属于物理删除,删除后没法进行恢复。
查询参数
CRUD
操做过程当中,都少不了的就是查询,细心的应该能够看的出,上面的例子中查询的时候多多少少的对其进行了一些小的改动。Sequelize
中有两种查询:使用Model
(模型)中的方法查询和使用sequelize.query()
进行基于SQL
语句的原始查询。上面用到的是Model
查询方式,接下来就详细的介绍一些经常使用的参数以及其表明的意义。
attributes - 属性与查询字段
查询时,若是只须要查询模型的部分属性,能够在经过在查询选项中指定attributes
实现。该选项是一个数组参数,在数组中指定要查询的属性便可,这个字段在上面进行查询的时候已经使用过了。
AaronTest.findOne({ where:{ id:6 }, raw:true, attributes:["id", "title", "description"] }).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
查询属性(字段)能够经过传入一个嵌套数据进行重命名,这里须要强调一下重命名所指的是对查询出的数据键值进行重命名处理,而不是更改数据表中的字段名称。
AaronTest.findOne({ where:{ id:2 }, attributes:["id", ["title","t"]], raw:true }).then((result) => { console.log(result) }).catch((error) => { console.log(error) }) // 注意这里t ↓ // { id: 2, t: '前端 | 0.8765218593370694' }
经过sequelize.fn
方法能够进行聚合查询,我的以为这个方法不太经常使用,可是仍是简单的介绍一下,这种查询方式是向当前查询内容中添加一个新的属性,而且查询的是列表仍是查询单条数据。
应用场景:
好比有不少商品,每一个商品都有本身的分类,根据id
进行查询了一个商品,可是与其同类的商品有多少?就可使用这个方法添加进去。下面例子中的count
则是添加进去属性的键。
AaronTest.findAll({ where:{ id:2 }, attributes: [ "id", ["title","t"], [sequelize.fn('COUNT', sequelize.col('id')), 'count'] ], raw:true }).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
可能有一种状况,当前所须要查询的表字段太多,可是只有一两个数据不想要,在attributes
数组中添加很长的字段名称,这样会显得代码很臃肿。attributes
不光能够为数组,还能够为对象在对象存在exclude
这个属性,这个属性就是剔除掉那些不想要的属性。
AaronTest.findOne({ where:{ id:2 }, attributes:{ exclude: ['id'] }, raw:true }).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
where - 指定筛选条件
上面的那么多例子中where
出现的次数最多了,除了增长数据不须要,其余的都须要用到where
条件,能够指定一个where
选项以指定筛选条件,where
是一个包含属性/值对对象,sequelize
会根据此对象生产查询语句的筛选条件。
where
的基础用法也就向上面那样,针对某些特定的条件进行查询处理。
AaronTest.findOne({ where:{ id:2 }, attributes:{ exclude: ['id'] }, raw:true }).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
就像上面那样简单的查询没法知足全部的业务需求,Sequelize
还提供了操做符以知足更多的查询条件,经常使用的操做符以下:
$and: {a: 5} // AND (a = 5) $or: [{a: 5}, {a: 6}] // (a = 5 OR a = 6) $gt: 6, // > 6 $gte: 6, // >= 6 $lt: 10, // < 10 $lte: 10, // <= 10 $ne: 20, // != 20 $not: true, // IS NOT TRUE $between: [6, 10], // BETWEEN 6 AND 10 $notBetween: [11, 15], // NOT BETWEEN 11 AND 15 $in: [1, 2], // IN [1, 2] $notIn: [1, 2], // NOT IN [1, 2] $like: '%hat', // LIKE '%hat' $notLike: '%hat' // NOT LIKE '%hat' $iLike: '%hat' // 包含'%hat' (case insensitive) (PG only) $notILike: '%hat' // 不包含'%hat' (PG only) $like: { $any: ['cat', 'hat']} // 像任何数组['cat', 'hat'] -也适用于iLike和notLike
limit/offset - 分页与限制返回结果数
在进行列表查询时,不能把查询道德全部数据所有返回出去,须要对数据进行分页处理。
// 获取 10 条数据(实例) AaronTest.findAll({ limit: 10 }) // 跳过 8 条数据(实例) AaronTest.findAll({ offset: 8 }) // 跳过 5 条数据并获取其后的 5 条数据(实例) AaronTest.findAll({ offset: 5, limit: 5 })
查询排序
order
选项用于查询结果的排序数据。排序时应该传入一个包含属性-排序方向的元组/数组,以保证正确的转义:
AaronTest.findAll({ order: [ // 转义 username 并对查询结果按 DESC 方向排序 ['username', 'DESC'], // 按 max(age) 排序 sequelize.fn('max', sequelize.col('age')), // 按 max(age) DESC 排序 [sequelize.fn('max', sequelize.col('age')), 'DESC'], // 按 otherfunction(`col1`, 12, 'lalala') DESC 排序 [sequelize.fn('otherfunction', sequelize.col('col1'), 12, 'lalala'), 'DESC'], // 按相关联的User 模型的 name 属性排序 [User, 'name', 'DESC'], // 按相关联的User 模型的 name 属性排序并将模型起别名为 Friend [{model: User, as: 'Friend'}, 'name', 'DESC'], // 按相关联的User 模型的嵌套关联的 Company 模型的 name 属性排序 [User, Company, 'name', 'DESC'], ] // 如下全部声明方式都会视为字面量,应该当心使用 order: 'convert(user_name using gbk)' order: 'username DESC' order: sequelize.literal('convert(user_name using gbk)') })
上面说的这些对于SQL
语句了解一些,都是很容理解,有些API
不经常使用也就没些,详细能够查看中文文档。
SQL语句查询
原始查询中有两种替换查询参数的方法,以:开头的参数的形式替换或以不命名以?替换。在选项对象中传递参数:
// 这里是sequelize,并非model sequelize.query('SELECT * FROM projects WHERE id = ?', { replacements: ['active'], type: sequelize.QueryTypes.SELECT } ).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
总结
以上是对sequelize
的api
进行了整理,虽然不太全面,熟练掌握上述API
能够作一个项目了,有关sequelize
的更多的用法我也在继续爬坑中,可能文章中有些许错误,你们能够在下方留言,我会尽快作出改正。感谢你们的阅读。