第七部分:第三节 - 在 Express 应用中集成 MySQL:厨房与仓库的直接对接

既然我们已经在纯 Node.js 中学会了如何连接和操作 MySQL,现在是时候将这个能力集成到 Express 应用中了。在 Express 中,我们通常会在应用启动时创建数据库连接或连接池,然后在需要访问数据库的路由处理函数中获取连接并执行查询。这就像在 Express 厨房管理系统中,直接配置好了通往原材料仓库的通道,厨师们(路由处理函数)可以直接通过这个通道获取所需的原材料。

在 Express 应用中配置数据库:

通常会在应用的入口文件或单独的配置文件中创建连接池,并使其在整个应用中可用。

// app.js (Express 应用)
const express = require('express');
const mysql = require('mysql2/promise'); // 使用 Promise 版本的驱动
const app = express();
const port = 3000;

// 数据库连接池配置 (通常从环境变量或配置文件读取)
const dbConfig = {
  host: 'localhost',
  user: '',
  password: '',
  database: 'my_webapp_db',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
};

// 创建数据库连接池
const pool = mysql.createPool(dbConfig);

// 使连接池在所有路由和中间件中可用 (通过添加到 req 或 app 对象)
// 更优雅的方式是创建一个数据库模块或服务 (在 NestJS 中更常见)
app.locals.dbPool = pool; // 将连接池挂载到 app.locals 上,可以在任何地方通过 req.app.locals.dbPool 访问

// ... 其他中间件 (如 morgan, cors, body-parser) ...

// 定义路由
app.get('/users', async (req, res) => {
  let connection;
  try {
    // 从连接池获取连接
    connection = await req.app.locals.dbPool.getConnection();
    console.log(`连接 ID ${connection.threadId} 从连接池获取 (Express 路由)`);

    // 执行查询
    const [rows] = await connection.execute('SELECT * FROM users');

    // 发送 JSON 响应
    res.json(rows);

  } catch (err) {
    console.error('查询用户出错:', err);
    res.status(500).send('服务器内部出错'); // 发送 500 错误响应
  } finally {
    // 确保连接归还
    if (connection) {
      connection.release();
      console.log(`连接 ID ${connection.threadId} 归还给连接池 (Express 路由)`);
    }
  }
});

// ... 其他路由 ...

// 在应用关闭时关闭连接池 (可选,但推荐)
process.on('SIGINT', async () => {
    console.log('应用接收到 SIGINT 信号,正在关闭连接池...');
    await pool.end();
    console.log('连接池已关闭,应用退出。');
    process.exit(0);
});


// 启动服务器
app.listen(port, () => {
  console.log(`Express 应用运行在 http://localhost:${port}`);
});

// 运行这个文件: node app.js
// 访问 http://localhost:3000/users

在路由处理函数中执行查询:

在路由处理函数中,通过之前挂载到 app.locals 上的连接池获取连接,然后使用 await connection.execute() 执行 SQL 查询。由于数据库操作是异步的,路由处理函数需要声明为 async,并在执行数据库操作前使用 await

处理异步查询结果并发送响应:

数据库查询结果通常在 Promise resolved 后返回。在 async 函数中,可以直接 await 查询结果,然后使用 res.json()res.send() 将结果发送给客户端。务必在 try...catch...finally 结构中处理错误,并在 finally 块中释放连接回连接池。

中间件或工具函数管理数据库连接:

将数据库连接池直接挂载到 app.locals 是一种简单的方式,但更好的做法是创建一个专门的数据库模块或工具函数来管理连接的获取和释放。这使得数据库相关的逻辑更加集中和可复用。

// db.js (简单的数据库工具函数)
const pool = require('./app').locals.dbPool; // 假设 app.js 导出了 app 实例,并且连接池挂载在 app.locals

async function query(sql, params) {
    let connection;
    try {
        connection = await pool.getConnection();
        const [rows] = await connection.execute(sql, params);
        return rows;
    } catch (err) {
        console.error('数据库查询出错:', err);
        throw err;
    } finally {
        if (connection) {
            connection.release();
        }
    }
}

module.exports = { query };

// 在路由中使用:
// const db = require('./db');
// app.get('/users', async (req, res) => {
//   try {
//     const users = await db.query('SELECT * FROM users');
//     res.json(users);
//   } catch (err) {
//     res.status(500).send('服务器内部出错');
//   }
// });

小结: 在 Express 应用中集成 MySQL 通常涉及创建连接池并在需要时获取和释放连接。使用 Promise API 和 async/await 可以优雅地处理异步数据库操作。将数据库交互逻辑封装在工具函数或模块中是更好的实践。

练习:

  1. 在你之前的 Express 项目中,安装 mysql2
  2. app.js 中创建数据库连接池,并将其挂载到 app.locals
  3. 修改你之前创建的 /api/users GET 路由,使其从 MySQL 数据库的 users 表中获取所有用户并返回 JSON 响应。
  4. 修改你之前创建的 /api/users POST 路由,使其接收请求体中的用户数据,并使用 INSERT 语句将新用户插入到 users 表中。返回新用户的 ID 或整个用户对象,并设置 201 状态码。
  5. 为你的 /api/users/:userId GET 路由添加数据库查询逻辑,根据 ID 从数据库中查找用户并返回,如果找不到则返回 404。
  6. (可选)创建一个 db.js 文件,封装数据库查询逻辑,并在路由中调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

低代码布道师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值