本文你将看到:MySQL、SQL、ORM、Sequelize 在概念上的关系
Sequelize 的用法
Sequelize 中联表关系的概念、用法、原理、区别
如何优化数据库查询
1 概念
MySQL
大部分人对 MySQL、SQL 是有了解的,毕竟教科书里都写着。 MySQL 是一种典型的关系型数据库嘛,怎么叫关系呢?简单说,关系型数据库是由多张能互相联接的二维行列表格组成的数据库。
这里两个点:::二维行列表::(体现在个体表数据结构上)、::互相连接::(体现在表关系和库引擎特点上)。
相较于 MongoDB 这种 NoSQL,二维行列表带来的优势在于:数据结构严谨带来的可靠:每一列的数据类型甚至大小都被模型定义,一切稳稳当当
「平层」带来的理解便利:每一条数据都是「平层」的,毕竟自由嵌套读起来真的太南了
SQL
既然关系型数据库是一个统一的标准,那只要各家都按标准实现,剩下的事就可以统一了,比如对数据库的访问。
SQL 就是干这个的,它只是一句字符串,可以理解为一个命令,在关系型数据库上做任何操作,但考虑关系设计已经把复杂的事情简单化,SQL 无非就做这么几件事:对库、表本身,以及表之间的关系进行定义
在一张表内增删改查
借助表间关系,一次性联合访问多张表中数据
访问一些基础的运算函数
总之这样一些拼起来,理论上你就能「只用一句SQL」为所欲为了。 了解更多:按我的知识水平,只能读 《菜鸟教程》
ORM 和 Sequlize
但 SQL 是远远不够的,因为字符串本身没有任何约束可言,你可能想查一个数据,结果一手抖打错把库删了,就只能跑路了。另外在代码里写一堆字符串着实丑陋。
所以出来一种叫 ORM 的东西,什么是 ORM 呢?字面上意思是::「对象关系映射」::,有点绕。
其实就是把数据库表映射成语言对象;然后暴露出一堆方法用来查库,ORM 负责把方法调用转成 SQL;因为表中的记录就是 key - value 形式,所以查询到的返回结果通常也是个对象,方便使用数据。这样对数据库访问的便捷性和稳定性都得到了提高。
方法 SQL
业务逻辑 ORM 数据库
数据对象 数据
然而 ORM 只是一个解决方案。在右侧,不受数据库类型限制,只要是遵循 SQL 的关系型数据库都得到支持;在左侧,不受语言类型限制,各家都有相对成熟的实现方案,甚至会根据语言特性增加一些语言层面的优化支持。
在 nodejs 中,「Sequlizejs」可能是最出类拔萃的 ORM 实现。植根于 nodejs,Sequlizejs 完美支持 Promise 式调用,进一步你可以走 async/await,和业务代码紧密粘合;如果上了 ts,从模型定义带来的类型提醒能让调用更省心。
2 基础用法
表/模型的定义
前面提到,ORM 的第一步就是要建立对象到数据表的映射,在 Sequlize 里是这样的,比如我们关联一个 station 的表
const Model = sequlize.define('station', {
id: {
field: 'id',
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
store_id: Sequelize.STRING(20),
name: Sequelize.STRING(20),
type: Sequelize.TINYINT,
status: Sequelize.TINYINT,
ip: Sequelize.STRING(20),
plate_no: Sequelize.STRING(20),
related_work_order_id: Sequelize.BIGINT,
});
可见在定义过程中,数据类型是从 Sequelize 静态属性上引用的。这些类型能覆盖数据库里的类型,但命名并非对应的,具体参考:lib/data-types.js
你也可以通过 define 的第三个参数做一些自定义,这些配置会被合并到 Sequlize 构造函数的 define 字段中,用来定义模型和数据表的关联行为,比如「自动更新表中的 update_at、create_at」。参考 Model | Sequelize 中的 options
但是模型归模型,是给 ORM 用的,数据库里的表还是要自己去建的。通过客户端或如下这种建表 SQL:
CREATE TABLE `station` (
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`store_id` varchar(20) NOT NULL DEFAULT '',
`name` varchar(20) NOT NULL DEFAULT '',
`type` tinyint(4) NOT NULL DEFAULT '0',