专栏首页图雀社区Nest.js 从零到壹系列(二):数据库的连接

Nest.js 从零到壹系列(二):数据库的连接

本文由图雀社区认证作者 布拉德特皮 写作而成,点击阅读原文查看作者掘金链接,感谢作者的优质输出,让我们的技术世界变得更加美好?

前言

上一篇介绍了如何创建项目、路由的访问以及如何创建模块,这篇来讲讲数据库的连接与使用。

既然是后端项目,当然要能连上数据库,否则还不如直接写静态页面。

本教程使用的是 MySQL,有人可能会问为啥不用 MongoDB。。。呃,因为公司使用 MySQL,我也是结合项目经历写的教程,MongoDB 还没踩过坑,所以就不在这误人子弟了。

GitHub 项目地址[1],欢迎各位大佬 Star。

一、MySQL 准备

首先要确保你有数据库可以连接,如果没有,可以在 MySQL 官网下载一个,本地跑起来。安装教程这里就不叙述了,“百度一下,你就知道”。

推荐使用 Navicat Premium 可视化工具来管理数据库。

用 Navicat 连接上数据库后,新建一个库:

点开我们刚创建的库 nest_zero_to_one,点开 Tables,发现里面空空如也,接下来我们创建一张新表,点开上面工具栏的 Query,并新增查询:

将下列代码复制到框内,点击上面的运行,即可完成表的创建:

CREATE TABLE `admin_user` (
  `user_id` smallint(6) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `account_name` varchar(24) NOT NULL COMMENT '用户账号',
  `real_name` varchar(20) NOT NULL COMMENT '真实姓名',
  `passwd` char(32) NOT NULL COMMENT '密码',
  `passwd_salt` char(6) NOT NULL COMMENT '密码盐',
  `mobile` varchar(15) NOT NULL DEFAULT '0' COMMENT '手机号码',
  `role` tinyint(4) NOT NULL DEFAULT '3' COMMENT '用户角色:0-超级管理员|1-管理员|2-开发&测试&运营|3-普通用户(只能查看)',
  `user_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态:0-失效|1-有效|2-删除',
  `create_by` smallint(6) NOT NULL COMMENT '创建人ID',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by` smallint(6) NOT NULL DEFAULT '0' COMMENT '修改人ID',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`user_id`),
  KEY `idx_m` (`mobile`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='后台用户表';

然后我们可以看到,左边的 Tables 下多出了 admin_user 表,点开就可以看到字段信息了:

我们先随便插入2条数据,方便后面的查询:

二、项目的数据库配置

先在项目根目录创建一个文件夹 config(与 src 同级),专门放置各种配置。

然后新建一个文件 db.ts:

// config/db.ts
const productConfig = {
  mysql: {
    port: '数据库端口',
    host: '数据库地址',
    user: '用户名',
    password: '密码',
    database: 'nest_zero_to_one', // 库名
    connectionLimit: 10, // 连接限制
  },
};

const localConfig = {
  mysql: {
    port: '数据库端口',
    host: '数据库地址',
    user: '用户名',
    password: '密码',
    database: 'nest_zero_to_one', // 库名
    connectionLimit: 10, // 连接限制
  },
};

// 本地运行是没有 process.env.NODE_ENV 的,借此来区分[开发环境]和[生产环境]
const config = process.env.NODE_ENV ? productConfig : localConfig;

export default config;

Ps:这个文件是不同步到 github 的,需要各位读者结合实际情况配置

市面上有很多连接数据库的工具,笔者这里使用的是 Sequelize,先安装依赖包:

$ npm i sequelize sequelize-typescript mysql2 -S
或
$ yarn add sequelize sequelize-typescript mysql2 -S

然后在 src 目录下创建文件夹 database,然后再创建 sequelize.ts

// src/database/sequelize.ts
import { Sequelize } from 'sequelize-typescript';
import db from '../../config/db';

const sequelize = new Sequelize(db.mysql.database, db.mysql.user, db.mysql.password || null, {
  // 自定义主机; 默认值: localhost
  host: db.mysql.host, // 数据库地址
  // 自定义端口; 默认值: 3306
  port: db.mysql.port,
  dialect: 'mysql',
  pool: {
    max: db.mysql.connectionLimit, // 连接池中最大连接数量
    min: 0, // 连接池中最小连接数量
    acquire: 30000,
    idle: 10000, // 如果一个线程 10 秒钟内没有被使用过的话,那么就释放线程
  },
  timezone: '+08:00', // 东八时区
});

// 测试数据库链接
sequelize
  .authenticate()
  .then(() => {
    console.log('数据库连接成功');
  })
  .catch((err: any) => {
    // 数据库连接失败时打印输出
    console.error(err);
    throw err;
  });

export default sequelize;

三、数据库连接测试

好了,接下来我们来测试一下数据库的连接情况。

我们重写 user.service.ts 的逻辑:

// src/logical/user/user.service.ts
import { Injectable } from '@nestjs/common';
import * as Sequelize from 'sequelize'; // 引入 Sequelize 库
import sequelize from '../../database/sequelize'; // 引入 Sequelize 实例

@Injectable()
export class UserService {
  async findOne(username: string): Promise<any | undefined> {
    const sql = `
      SELECT
        user_id id, real_name realName, role
      FROM
        admin_user
      WHERE
        account_name = '${username}'
    `; // 一段平淡无奇的 SQL 查询语句
    try {
      const res = await sequelize.query(sql, {
        type: Sequelize.QueryTypes.SELECT, // 查询方式
        raw: true, // 是否使用数组组装的方式展示结果
        logging: true, // 是否将 SQL 语句打印到控制台,默认为 true
      });
      const user = res[0]; // 查出来的结果是一个数组,我们只取第一个。
      if (user) {
        return {
          code: 200, // 返回状态码,可自定义
          data: {
            user,
          },
          msg: 'Success',
        };
      } else {
        return {
          code: 600,
          msg: '查无此人',
        };
      }
    } catch (error) {
      return {
        code: 503,
        msg: `Service error: ${error}`,
      };
    }
  }
}

保存文件,就会看到控制台刷新了(前提是使用 yarn start:dev 启动的),并打印下列语句:

这说明之前的配置生效了,我们试着用之前的参数请求一下接口:

返回“查无此人”,说明数据库没有叫“Kid”的用户。

我们改成正确的已存在的用户名再试试:

然后观察一下控制台,我们的查询语句已经打印出来了,通过 logging: true,可以在调试 Bug 的时候,更清晰的查找 SQL 语句的错误,不过建议测试稳定后,上线前关闭,不然记录的日志会很繁杂:

再对照一下数据库里的表,发现查出来的数据和数据库里的一致,至此,MySQL 连接测试完成,以后就可以愉快的在 Service 里面搬砖了。

总结

这篇介绍了 MySQL 的数据准备、Sequelize 的配置、Nest 怎么通过 Sequelize 连接上 MySQL,以及用一条简单的查询语句去验证连接情况。

在这里,强烈建议使用写原生 SQL 语句去操作数据库

虽然 Sequelize 提供了很多便捷的方法,具体可去 Sequelize v5 官方文档[2] 浏览学习。但笔者通过观察 logging 打印出来的语句发现,其实多了很多无谓的操作,在高并发的情况下,太影响性能了。

而且如果不使用原生查询,那么就要建立对象映射到数据库表,然后每次工具更新,还要花时间成本去学习,如果数据库改了字段,那么映射关系就会出错,然后项目就会疯狂报错以致宕机(亲身经历)。

而使用原生 SQL,只需要学一种语言就够了,换个工具,也能用,而且就算改了字段,也只会在请求接口的时候报错,到时候再针对那个语句修改就好了,而且现在查找替换功能这么强大,批量修改也不是难事。

最重要的是,如果你是从前端转后端,或者根本就是0基础到后端,还是建议先把 SQL 的基础打牢,不然连 JOINLEFT JOINRIGHT JOIN 的区别都分不清(我们公司就有个三年经验的后端,乱用 LEFT JOIN,然后被 DB 主管一顿痛骂。。。真事儿)。

多写、多分析、多看控制台报错、多从性能上考虑,才是最快入门的途径。

注意:在写 UPDATE 更新语句的时候,一定要加上 WHERE 条件,一定要加上 WHERE 条件,一定要加上 WHERE 条件,重要的事情说3遍,血与泪的教训!!!

下一篇,将介绍如何使用 JWT(Json Web Token)进行单点登录。

参考资料

[1]

GitHub 项目地址: https://github.com/SephirothKid/nest-zero-to-one

[2]

Sequelize v5 官方文档: https://sequelize.org/v5/

● Nest.js 从零到壹系列(一):项目创建&路由设置&模块● 爬虫养成记--顺藤摸瓜回首掏(女生定制篇)● 前端工程师的自我修养-关于 Babel 那些事儿

·END·

本文分享自微信公众号 - 图雀社区(tuture-dev),作者:布拉德特皮

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-03-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 使用 Electron + Vue 打造一个有道云笔记桌面端应用(五):优化前端展示、组件设计和数据库的细节

    上一篇我们已经完成了数据持久化,使得我们创建的 Markdown 笔记得以保存,这一篇我们就开始实打实地创建 Markdown 笔记了。? ❞

    一只图雀
  • 一杯茶的时间,上手 Koa2 + MySQL 开发

    凭借精巧的“洋葱模型”和对 Promise 以及 async/await 异步编程的完全支持,Koa 框架自从诞生以来就吸引了无数 Node 爱好者。然而 Ko...

    一只图雀
  • 前端学习数据结构与算法系列(七):堆排序与归并排序

    堆排序相比冒泡排序、选择排序、插入排序而言,排序效率是最高的,本文从堆的属性和特点出发采用图文形式进行讲解并用JavaScript将其实现,欢迎各位感兴趣的开发...

    一只图雀
  • 产品的成败,关键在设计!

    在不到一秒钟的时间内,决策就已经开始了。人是视觉动物。因此设计对说服人的工作效果影响巨大。设计影响着受众对内容的第一印象,影响着用户的消费决策和营销效果。 在你...

    BestSDK
  • git: 用 ssh协议 代替 http协议,加速传送

    每次在实验室往服务器push修改,要么是 git push origin matser 试个好几次,要么就是报错如下:

    JNingWei
  • GitHub 系列之「Git 进阶」1.用户名和邮箱2.alias3.其他配置4.diff5.checkout后面的一长串是commit_id,是每次commit的SHA1值,可以根据 git log

    我们知道我们进行的每一次 commit 都会产生一条 log,这条 log 标记了提交人的姓名与邮箱,以便其他人方便的查看与联系提交人,所以我们在进行提交代码的...

    意气相许的许
  • git 如何将dev merge到master上

    之前开发主要是在dev上,从master上clone下代码,开发完以后提交到dev交由测试测完没问题,再由项目经理merge到master上(生产环境).如今自...

    编程软文
  • git 如何将dev merge到master上

    之前开发主要是在dev上,从master上clone下代码,开发完以后提交到dev交由测试测完没问题,再由项目经理merge到master上(生产环境).如今自...

    编程软文
  • 扔掉压缩工具,让我们用 Python 管理压缩包。

    压缩包是互联网上软件发布的标准格式,同时对于系统管理很有用处。当我们需要将多份文件发送给别人的时候,最好通过压缩包的形式发送,还有在备份某些文件的时候,为了减少...

    Rocky0429
  • Git基本命令

    git push -u origin 分支名字 -f // -f强制提交,一般不用,但第一次提交会提示我们版本过低

    秋雨

扫码关注云+社区

领取腾讯云代金券