Nest.js 從零到壹系列(二):數據庫的鏈接

前言

上一篇介紹瞭如何建立項目、路由的訪問以及如何建立模塊,這篇來說講數據庫的鏈接與使用。前端

既然是後端項目,固然要能連上數據庫,不然還不如直接寫靜態頁面。mysql

本教程使用的是 MySQL,有人可能會問爲啥不用 MongoDB。。。呃,由於公司使用 MySQL,我也是結合項目經歷寫的教程,MongoDB 還沒踩過坑,因此就不在這誤人子弟了。git

1、MySQL 準備

首先要確保你有數據庫能夠鏈接,若是沒有,能夠在 MySQL 官網下載一個,本地跑起來。安裝教程這裏就不敘述了,「百度一下,你就知道」。github

推薦使用 Navicat Premium 可視化工具來管理數據庫。sql

用 Navicat 鏈接上數據庫後,新建一個庫:typescript

點開咱們剛建立的庫 nest_zero_to_one,點開 Tables,發現裏面空空如也,接下來咱們建立一張新表,點開上面工具欄的 Query,並新增查詢:數據庫

將下列代碼複製到框內,點擊上面的運行,便可完成表的建立:npm

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條數據,方便後面的查詢:數組

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;
複製代碼

3、數據庫鏈接測試

好了,接下來咱們來測試一下數據庫的鏈接狀況。

咱們重寫 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 官方文檔 瀏覽學習。但筆者經過觀察 logging 打印出來的語句發現,其實多了不少無謂的操做,在高併發的狀況下,太影響性能了。

並且若是不使用原生查詢,那麼就要創建對象映射到數據庫表,而後每次工具更新,還要花時間成本去學習,若是數據庫改了字段,那麼映射關係就會出錯,而後項目就會瘋狂報錯以至宕機(親身經歷)。

而使用原生 SQL,只須要學一種語言就夠了,換個工具,也能用,並且就算改了字段,也只會在請求接口的時候報錯,到時候再針對那個語句修改就行了,並且如今查找替換功能這麼強大,批量修改也不是難事。

最重要的是,若是你是從前端轉後端,或者根本就是0基礎到後端,仍是建議先把 SQL 的基礎打牢,否則連 JOINLEFT JOINRIGHT JOIN 的區別都分不清(咱們公司就有個三年經驗的後端,亂用 LEFT JOIN,而後被 DB 主管一頓痛罵。。。真事兒)。

多寫、多分析、多看控制檯報錯、多從性能上考慮,纔是最快入門的途徑。

注意:在寫 UPDATE 更新語句的時候,必定要加上 WHERE 條件,必定要加上 WHERE 條件,必定要加上 WHERE 條件,重要的事情說3遍,血與淚的教訓!!!

下一篇,將介紹如何使用 JWT(Json Web Token)進行單點登陸。

`

相關文章
相關標籤/搜索