Skip to content

❤项目优化(番外篇)

查询接口优化

查询接口条件优化(文章)

这里我们以文章模块为例,之前我们查询接口是这样子的

javascript

// 标题
if (title !== undefined && title !== '' && title !== null) {
    query += ' WHERE title = ?';
    params.push(title);
}
// 类型
if (articletype !== undefined && articletype !== '' && articletype !== null) {
    query += params.length ? ' AND' : ' WHERE';
    query += ' articletype = ?';
    params.push(articletype);
}

if (pageNum !== undefined && pageSize !== '' && pageSize !== null) {
    query += ' LIMIT ?, ?';
    let offset = (pageNum - 1) * pageSize;
    params.push(offset);
    params.push(parseInt(pageSize));
}

我们写了公开函数方法进行优化

优化之后就成为了:

javascript
const {addCondition,addDateRangeCondition,addPagination} = require('./apimethods.js'); // 引入封装方法


// 构建查询条件
const params = [];
query = addCondition(query, params, 'title', title); // 标题
query = addCondition(query, params, 'articletype', articletype);  // 类型
query = addPagination(query, params, pageNum, pageSize);  //分页条件

新增接口优化

新增接口条件默认值优化(用户接口)

接下来我们对于用户接口部分我们进行一些优化

javascript
export function editUserStatus (n) {
    return request({
            url: '/api/user/status',
            method: 'put',
            data:n
    })
}

向其中插入一个SQL语句尝试一下

javascript
INSERT INTO user (name, age,state) VALUES ('lin', 18,1)

如果前台的参数没有传,那么默认会出现一种情况

javascript
用户前面判断显示可以使用,但是用户其实真实状态是null

如何添加一个用户,然后默认这个用户角色是可以正常使用的呢?

这就需要我们改一下我们的增加用户的接口,这个接口使默认用户权限是初始化打开的

我们将 0 为初始化可以使用 1 为正常使用 2 为禁用以后

☞ 新增用户接口优化

javascript
// 准备 SQL 插入语句
const insertSql = `INSERT INTO user (name, age,state) VALUES (?, ?,1)`;

禁用和启用接口分离(用户模块)

javascript
app.put('/api/user/status', (req, res) => {
    // console.log(req.body);
    const { name, age } = req.body; // 从请求体中获取数据
    const values = [state];
    // 准备 SQL 插入语句
    const insertSql = `UPDATE user SET state = ?`;
    connectionpool.query(insertSql, values, (err, results) => {
        // console.log(err,'err');
        // console.log(results,'results');
        if (err) {
            console.error('Error querying database:', err);
            res.status(500).json({ error: 'Internal server error' });
            return;
        }
        res.json({
            code: '200',
            data: results,
        });
    });
});

查询接口返回条数页数优化

以我们字典类型模块的接口为例,不管有没有在添加查询参数条件的情况下查到数据,都会返回total,这种是错误的,

如果查询不到数据,total应该返回0,这样前端才能知道是否查询到数据了,所以这里我们修改一下,也就是针对已经查询完之后的查询部分进行更改

javascript

// 字典值type接口
// 查询接口
router.get('/', (req, res) => {

    console.log(req.query, 'req.query');
  
    const { dict_name, dict_type, status,page_num, page_size,begin_time,end_time} = convertKeysToSnakeCase(req.query);

    let query = `SELECT * FROM sys_dict_type`;

    // 构建查询条件
    const params = [];
    query = addCondition(query, params, 'dict_name', dict_name); // 字典名称
    query = addCondition(query, params, 'dict_type', dict_type);  // 字典类型
    query = addCondition(query, params, 'status', status);  // 状态
    // query = addCondition(query, params, 'dict_label', dict_label); // 字典标签
    query = addDateRangeCondition(query, params, begin_time, end_time); //查询时间
    query = addPagination(query, params, page_num, page_size);  //分页条件

  
    console.log(query,'query');

    connectionPool.query(query,params,(error, results, fields) => {
         if (error) {
          res.send({
              code: 500,
              message:'查询失败!',
          });
          res.status(500).json({ error: error.message });
        } else {

            let sqltotal = `SELECT COUNT(*) AS total FROM sys_dict_data;`
            // 查询数据库并返回数据
            connectionPool.query(sqltotal, (errtotal, rows) => {
                let total = rows[0]['total'];
                if (errtotal) {
                    console.error('Error querying database:', err);
                    res.status(500).json({ error: 'Internal server error' });
                    return;
                } else {
                    res.send({
                        total: total,
                        code: 200,
                        data: convertToCamelCase(results),
                        message:'查询成功!',
                    });
                }
            });
        }
    });
});

=> 判断一下是否查询到空数组

js
if(results.length>0){
        let sqltotal = `SELECT COUNT(*) AS total FROM sys_dict_data;`
        // 查询数据库并返回数据
        connectionPool.query(sqltotal, (errtotal, rows) => {
            let total = rows[0]['total'];
            if (errtotal) {
                console.error('Error querying database:', err);
                res.status(500).json({ error: 'Internal server error' });
                return;
            } else {
                res.send({
                    total: total,
                    code: 200,
                    data: convertToCamelCase(results),
                    message:'查询成功!',
                });
            }
        });
}else{
      res.send({
        total: 0,
        code: 200,
        data: [],
        message:'查询成功!',
    });
}

2、Node文件内置模块fs的认识

Node.js内置模块fs(文件系统)用于处理文件系统相关的操作,为Node.js提供了处理文件系统的能力,使Node.js能够在服务器端进行文件相关的操作,读取配置文件、处理日志、操作文件数据库等

  1. 读取文件:使用fs.readFile()fs.readFileSync()方法来读取文件内容。
  2. 写入文件:使用fs.writeFile()fs.writeFileSync()方法来将数据写入文件。
  3. 追加文件:使用fs.appendFile()方法向文件中追加数据。
  4. 删除文件:使用fs.unlink()方法可以删除文件。
  5. 创建目录:使用fs.mkdir()方法创建目录。
  6. 删除目录:使用fs.rmdir()方法删除目录。
  7. 重命名文件或目录:使用fs.rename()方法可以重命名文件或目录。
  8. 检查文件或目录的存在性:使用fs.access()方法检查文件或目录是否存在。
  9. 获取文件或目录的信息:使用fs.stat()方法获取文件或目录的信息,如大小、创建时间等。

3、文件模块化优化

在 Node.js 中,可以通过模块化的方式将接口分为不同的模块进行导入,这样子我们的模块可以进行不同的导入以及导导出,使接口模块化和易于维护

新建一个productRoutes.js

javascript
const express = require('express');
const router = express.Router();

// 定义产品相关接口
router.get('/products', (req, res) => {
  // 处理获取产品列表的逻辑
});

router.post('/products', (req, res) => {
  // 处理创建产品的逻辑
});

module.exports = router;

在之前的app.js根目录之中进行引入

javascript
const express = require('express');
const app = express();
const userRoutes = require('./userRoutes');
const productRoutes = require('./productRoutes');

// 将用户相关接口模块挂载到 /api/user 路径下
app.use('/api/user', userRoutes);

// 将产品相关接口模块挂载到 /api/product 路径下
app.use('/api/product', productRoutes);

// 启动服务
app.listen(8888, () => {
  console.log('Server is running on port 3000');
});

接下来我们尝试访问一下

javascript
[http://localhost:8888/api/product](http://localhost:8888/api/product)

结果显示我们报错404

image.png

分析,我们使用的地址前面注意是/api/product,然后在我们的项目之中再次添加了/products ,也就是说我们正常的路径其实应该是/api/product/products,访问地址http://localhost:8888/api/product/products这个时候我们发现,接口已经可以正常输出了!

javascript
app.use('/api/product', productRoutes);

image.png

(1)抽离数据库模块为db.js

javascript
// 创建数据库连接池 createPool(高并发方式)
const mysql = require('mysql');
// 创建数据库连接池
const connectionPool = mysql.createPool({
    host: 'localhost', // 数据库主机地址,如果是本地数据库则使用localhost
    user: 'xxxx', // 数据库用户名
    password: 'xxxx', // 数据库密码
    database: 'xxx', // 要连接的数据库名
    multipleStatements: true, //  允许执行多条语句
});

module.exports = connectionPool;

在根之中导入使用

javascript
const connectionPool = require('./server/db'); // 引入数据库连接池模块

剩下的就跟砸门之前connectionPool的正常使用一样

这里有个小插曲,就是我分离模块以后一直报500的错误,最后找了几个小时发现是单词拼写错了🤮

javascript
connectionPool  我给拼写成了connectionpool

所以要谨慎再谨慎啊

(2)抽离用户模块为 userRoutes.js

需要注意的就是路径的变化和接口的使用方式的变化

javascript

之前我们使用:/api/user
// 新增用户 POST 请求处理程序 
app.post('/api/user', (req, res) => {
    // console.log(req.body);
    const { name, age } = req.body; // 从请求体中获取数据
    const values = [name, age];
    // 准备 SQL 插入语句
    const insertSql = `INSERT INTO user (name, age,state) VALUES (?, ?,1)`;
    connectionPool.query(insertSql, values, (err, results) => {
        // console.log(err,'err');
        // console.log(results,'results');
        if (err) {
            console.error('Error querying database:', err);
            res.status(500).json({ error: 'Internal server error' });
            return;
        }
        res.json({
            code: '200',
            data: results,
        });
    });
});



现在我们使用:/
// 新增用户 POST 请求处理程序 
router.post('/', (req, res) => {
    // console.log(req.body);
    const { name, age } = req.body; // 从请求体中获取数据
    const values = [name, age];
    // 准备 SQL 插入语句
    const insertSql = `INSERT INTO user (name, age,state) VALUES (?, ?,1)`;
    connectionPool.query(insertSql, values, (err, results) => {
        // console.log(err,'err');
        // console.log(results,'results');
        if (err) {
            console.error('Error querying database:', err);
            res.status(500).json({ error: 'Internal server error' });
            return;
        }
        res.json({
            code: '200',
            data: results,
        });
    });
});

引入和使用用户模块部分就更改为了:

javascript
const userRoutes = require('./server/api/userRoutes'); // 引入用户路由模块

// 使用用户路由
app.use('/api/user', userRoutes);

测试一下,功能正常

(3)抽离文章模块为 articleRoutes.js

articleRoutes.js大致如下

javascript
const express = require('express');
const router = express.Router();
const connectionPool = require('../db'); // 引入数据库连接池模块

.....
module.exports = router;

同样在我们的根目录之中进行使用:

javascript
// 引入文章模块
const articleRoutes = require('./server/api/articleRoutes'); 


// 使用文章接口
app.use('/api/articles', articleRoutes);

测试一下,没问题

文章数据增加

数据增加接口优化

javascript
const insertSql = `INSERT INTO articles (title, author,articlestatus) VALUES (?, ?,1)`;

const { title, author,articletype,articlestatus } = req.body; // 从请求体中获取数据
const values = [title, author,articletype,1];
const insertSql = 'INSERT INTO articles SET ?'; // 准备 SQL 插入语句

文章图片访问

image.png

图片太大了 ,存不进去,这个时候更改我们图片存储字段(为了存储base64位的图片)

改数据库thumburl的数据类型为LONGTEXT,以便能够存储较长的字符串。

5、返回数据规范

之前我们返回的数据都没有规范,现在我们定义一个返回接口的规范,用来规范返回数据

javascript
// 类型推断
interface ApiResponse {
    code: number;
    message: string;
}
import axios, { AxiosResponse } from 'axios';

cors模块跨域优化

javascript
app.options('*', cors()); // 这将在所有路由上启用 CORS 的预检请求处理

数据库监测完善

之前我们只是监测了数据库连接,现在我们监测一下数据库的查询情况,这部分我们也是放入我们的db.js数据库文件中

javascript
const connectionPool = mysql.createPool({
    host: 'localhost',
    user: 'root',
    password: 'root',
    database: 'myblog',
    connectionLimit: 10, // 设置连接池的最大连接数
    waitForConnections: true, // 当连接池中没有可用连接时,是否等待新的连接被创建
    queueLimit: 0 // 当连接池已满且没有可用连接时,新请求是否排队等待
});

// 监测数据库连接状态
connectionPool.getConnection((err, connection) => {
    if (err) {
        console.error('林太白数据库连接失败😢:', err);
    } else {
        console.log('林太白数据库连接成功😊');
    }
});

编写错误中间件

需要编写一个错误中间件,用来抛出错误,防止因为错误而造成接口崩溃

注意:错误中间件一定要放在所有路由之后

(1) 在所有路由之后放置中间件

js
app.use((err, req, res, next) => {
  // 如果错误是由token解析失败导致的
  if (err.name === 'UnauthorizedError') {
    return res.send({
      status: 401,
      message: '无效的token'
    })
  }
  // 如果是其他位置原因导致的错误
  res.send({
    status: 500,
    message: '未知的错误'
  })
  next()
})

(2)我们请求本地的接口尝试

JS
http://localhost:8888/api/user/5`

最后我们输出结果为:

js
{"code":401,"message":"无效的token"}

命名优化

mysql之中比较规范的命名是蛇形命名法

js
create_time

前端之中比较友好规范的命名是驼峰命名法

js
createTime

那么我们Node之中如何将蛇形命名法转化为驼峰命名法:

js
create_time => createTime

第一种方式:(这种方式我们局部使用正好)

js
function camelToSnake(str) {
  return str.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
}

第二种方式:(全局使用)

js
function camelToSnakeObject(obj) {
  if (Array.isArray(obj)) {
    return obj.map(camelToSnakeObject);
  } else if (obj !== null && typeof obj === 'object') {
    return Object.keys(obj).reduce((acc, key) => {
      const newKey = key.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
      acc[newKey] = camelToSnakeObject(obj[key]);
      return acc;
    }, {});
  }
  return obj;
}

//使用
// 示例
const camelCaseObj = {
  noticeContent: 'Some content',
  createdAt: '2024-12-27',
  userInfo: {
    firstName: 'John',
    lastName: 'Doe'
  }
};
const snakeCaseObj = camelToSnakeObject(camelCaseObj);
console.log(snakeCaseObj);

添加参数(驼峰命名法转换为蛇形命名法)

项目之中结合使用

JS
// 驼峰命名法(前端使用)=>蛇形命名法(sql数据库使用)
function camelToSnake(str) {
  return str.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
}
function convertKeysToSnakeCase(obj) {
  if (Array.isArray(obj)) {
    return obj.map(convertKeysToSnakeCase);
  } else if (obj !== null && typeof obj === 'object') {
    return Object.keys(obj).reduce((acc, key) => {
      const newKey = camelToSnake(key);
      acc[newKey] = convertKeysToSnakeCase(obj[key]);
      return acc;
    }, {});
  }
  return obj;
}
module.exports = {
    convertKeysToSnakeCase
};

//引入使用

const {  convertKeysToSnakeCase } = require('../methods.js'); // 引入封装方法

const postData = convertKeysToSnakeCase({ 
        noticeTitle,
        noticeType,
        noticeContent,
        status,
        createBy,
        createTime,
        updateBy,
        updateTime,
        remark
});

这里得到的postData里面的参数其实就已经是我们过滤过的数据了

查询参数(蛇形命名法转换为驼峰命名法)

同样,我们把查询出来的方法也更改为驼峰命名法

JS


// 将蛇形命名法转换为驼峰命名法
function snakeToCamel(str) {
    return str.replace(/_([a-z])/g, (match, p1) => p1.toUpperCase());
}

// 递归转换对象的所有键为驼峰命名法
function convertToCamelCase(obj) {
    if (Array.isArray(obj)) {
        return obj.map(item => convertToCamelCase(item));  // 对数组进行递归处理
    } else if (obj !== null && typeof obj === 'object') {
        const newObj = {};
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                const newKey = snakeToCamel(key);
                newObj[newKey] = convertToCamelCase(obj[key]);  // 对每个键的值进行递归处理
            }
        }
        return newObj;
    }
    return obj;  // 如果是基础数据类型,直接返回
}

删除接口优化

之前我们的删除语句是这样子的,这种删除有个缺陷就是无法执行多个删除语句,只能删除一个

JS
// 统一使用 IN 语句删除,无论是单个还是多个ID
const sqlQuery = "DELETE FROM sys_notice WHERE notice_id = ?";

现在我们统一写法为IN字句的删除,多个和单个的删除都可以复用

JS
// 统一使用 IN 语句删除,无论是单个还是多个ID
const sqlQuery = 'DELETE FROM notices WHERE id IN (?)';

时间参数

在数据新增的时候,创建时间参数和更新时间参数应该是使用的现在的时间

mysql表的设计之中时间应该是

JS
CREATE TABLE notices (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    content TEXT NOT NULL,
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

在数据库表中,create_time 字段自动使用当前时间戳,插入时不需要显式传递。

但是每次更新时,需要手动设置 update_time 为当前时间,或者使用数据库的 ON UPDATE CURRENT_TIMESTAMP 来自动处理。

数据更新的时候,更新时间手动插入为:

JS
const updateTime = new Date();
update_time:new Date()

Node后台接口地址

Mac查看自己的ip

js
curl ifconfig.me

curl ipinfo.io/ip // 查看ip地址

ifconfig // 查看ip地址 inet

之前我们采取的后台地址都是http://localhost:8888这种方式,但是有明显的缺陷,就是只能本机访问,那么如果我们想要改成局域网可以访问的方式应该如何做呢

js
app.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});


=> 修改为:
const PORT = 8888;
const ip = '0.0.0.0'; 
app.listen(PORT,ip,() => {
    console.log(`Server is running on http://localhost:${PORT}`);
});

进一步封装接口模块

接下来我们抽离接口方法为一个单独的文件,方便我们后续的维护

简单抽离一下查询接口

☞ apimethods.js

JS
// 接口的公共方法部分
function addApi(queryData,sqltotal,req,res,querySearch) {
    // console.log(query,sqltotal,querySearch,'查询');
    let querySearchData=convertKeysToSnakeCase(querySearch);
    // 查询Sql
    let querySql=queryData;

    // console.log(querySearchData,'querySearchData');

    // 构建查询条件
    let params = [];
    Object.keys(querySearchData).forEach(key => {
        // console.log(key, querySearchData[key]);  // 输出:key 和对应的值
        if(key!='page_num'&&key!='page_size'){
            querySql = addCondition(querySql, params, key, querySearchData[key]);
        }
    });   
    if(querySearchData['page_num']&&querySearchData['page_size']){
       querySql = addPagination(querySql,params,querySearchData.page_num,querySearchData.page_size);  //分页条件 
    }

    console.log('查询条件', querySql, params);
    
    // 查询数据库并返回数据
    connectionPool.query(querySql,params, (err, results) => {
        // console.log(err,'err');
        // console.log(results,'results');
        if (err) {
            res.send({
                code: 500,
                // data: results,
                message:'添加失败!'
            });
             return ;
        } else {
            if(results.length>0){
                    // 查询数据库并返回数据
                    connectionPool.query(sqltotal, (errtotal, rows) => {
                        let total = rows[0]['total'];
                        if (errtotal) {
                            res.send({
                                code: 401,
                                // data: results,
                                message: '查询失败!'
                            });
                            return;
                        } else {
                            console.log('查询成功');
                            res.send({
                                total: total,
                                code: 200,
                                data:convertToCamelCase(results),
                                message: '查询成功!',
                            });
                        }
                    });
            }else{
                 res.send({
                    total: 0,
                    code: 200,
                    data: [],
                    message:'查询成功!',
                });
            }
        }
    });
}

☞ 使用起来

这么一看确实简单整洁了不少,5行代码就实现了一个查询接口

JS
router.get('/',(req, res) => {
    // console.log(req.query, 'req.query');
    // console.log(req.body,'req.body');
    // console.log(req.params,'req.params');
    // 查询数据库列表
    let query = `SELECT * FROM articles`;

    // 查询数据库总数
    let sqltotal = `SELECT COUNT(*) AS total FROM articles`

    // 查询数据库并返回数据
    const { title,type, page_num, page_size } = convertKeysToSnakeCase(req.query);

    let querySearch =  {title,type, page_num, page_size};
    addApi(query,sqltotal,req,res,querySearch);
});

抽离增加接口

JS

// 新增接口
function addApi(insertSql, res, postData) {
     connectionPool.query(insertSql, postData, (error, results, fields) => {
        // console.log(results,'results');
        // console.log(error,'error');
        if (error) {
            res.send({
                code: 500,
                error: error,
                message: '添加失败!'
            });
            return;
        } else {
            res.send({
                code: 200,
                // data: results,
                message: '添加成功!'
            });
            return;
        }
    });
}

使用

JS
// 新增  POST
router.post('/', (req, res) => {
  const insertSql = 'INSERT INTO articles SET ?'; // 准备 SQL 插入语句
  const { title, author,type,content} = convertKeysToSnakeCase(req.body);
  const postData = {title,author,type,status:1,content};
  addApi(insertSql,res,postData);
});

抽离详情接口

封装

JS
// 详情接口
function getApi(querySql,values,res) {
    connectionPool.query(querySql, values, (err, results) => {
        if (err) {
            console.error('Error querying database:', err);
            res.status(500).json({ error: 'Internal server error' });
            return;
        }
        res.json({
            code: 200,
            data: convertToCamelCase(results[0]) || {},
        });
    });
}

使用

JS
router.get('/:id', (req, res) => {
    // console.log(req.query,'req.query');
    const { id } = req.params;
    const values = [id];
    let querySql = 'SELECT * FROM articles WHERE id = ?';
    getApi(querySql,values,res);
});

抽离修改接口

JS
// 更新接口
function updateApi(updateSql,Search,res) {
     connectionPool.query(updateSql,Search, (error, results, fields) => {
        if (error) {
            res.send({
                code: 500,
                // data: results,
                error:error,
                message:'修改失败!'
            });
            return;
        } else {
            res.send({
                code: 200,
                // data: convertToCamelCase(results),
                message:'修改成功!'
            });
        }
    });
}

使用

JS
// 更新接口
router.put('/', (req, res) => {
  // console.log(req,'req');
  const { title, content,id} = convertKeysToSnakeCase(req.body);
  const updatevalues = {title, content};
  let updateSql='UPDATE articles SET ? WHERE id = ?';
  updateApi(updateSql,[updatevalues, id],res);
});

抽离删除接口

JS
// 更新接口
function delApi(delSql,delvalue,res) {
     connectionPool.query(delSql, delvalue, (error, results) => {
        if (error) {
            console.error('Error querying database:', error);
            res.status(500).json({ error: error });
            return;
        }
        res.json({
            code: 200,
            // data: results,
            message:'删除成功!',
        });
    });
}

使用

JS
// 删除数据 DELETE请求处理程序  
router.delete('/:id', (req, res) => {
    // const {id} = req.body; // 从请求体中获取数据
    const id = req.params.id;
    const delsql = "DELETE FROM articles WHERE id = ?";
    delApi(delsql,[id],res);
});

抽离更改状态接口

更改状态接口抽离

JS
// 更新状态接口
function changeStatusApi(statusSql,upvalue,res) {
    connectionPool.query(statusSql,upvalue, (error, results, fields) => {
        if (error) {
             res.json({
                code: 500,
                error: error,
                message:'更改失败!',
            });
            return;
        } else {
             res.json({
                code: 200,
                // data: results,
                message:'更改成功!',
            });
        }
    });
}

使用

JS
//  禁用和使用,用于更改状态
router.put('/status/:id', (req, res) => {
    const id = parseInt(req.params.id);
    const newState = req.body.status;
    const query = 'UPDATE articles SET status = ? WHERE id = ?';
    changeStatusApi(query,[newState, id],res);
});

mysql库优化为mysql2

之前我们使用的mysql库,现在我们使用mysql2库,因为mysql2库性能更高,并且支持promise,在mysql8.0中,mysql2库支持异步操作

JS
卸载之前的mysql
npm uninstall mysql

安装mysql2
npm install mysql2


使用mysql2库
const mysql = require('mysql'); 
// 创建数据库连接池
const connectionPool = mysql.createPool({
    host: 'xxx', // 数据库主机地址,如果是本地数据库则使用localhost
    user: 'xxx', // 数据库用户名
    password: 'xxx', // 数据库密码
    database: 'xxx', // 要连接的数据库名
    multipleStatements: true, //  允许执行多条语句
});

=> 只需要把对应模块给替换成我们的mysql2 即可

const mysql2 = require('mysql2'); 
// 创建数据库连接池
const connectionPool = mysql2.createPool({
    host: 'xxx', // 数据库主机地址,如果是本地数据库则使用localhost
    user: 'xxx', // 数据库用户名
    password: 'xxx', // 数据库密码
    database: 'xxx', // 要连接的数据库名
    multipleStatements: true, //  允许执行多条语句
});

Released under the MIT License.