第七部分:第二节 - 在 Node.js 中连接和操作 MySQL:厨房与仓库的沟通渠道

要让 Node.js 后端应用(厨房)与 MySQL 数据库(仓库)进行交互,我们需要一个数据库驱动程序 (Database Driver)。驱动程序就像厨房与仓库之间的通信员,它知道如何用仓库管理员(MySQL Server)能理解的语言(SQL)发送指令,并把仓库的回应(查询结果)带回来。

Node.js 有多个可用的 MySQL 驱动,比较流行且推荐的是 mysql2,它支持 Promise API,更适合现代异步编程风格。

安装 mysql2:

在你的 Node.js 项目目录中(非 NestJS 项目,先以纯 Node.js 脚本为例):

bash 复制代码
npm install mysql2
# 或者 yarn add mysql2

建立数据库连接:

在操作数据库之前,首先需要建立一个连接。连接信息包括数据库地址(host)、端口、用户名、密码、数据库名等。

javascript 复制代码
// connect_db.js
const mysql = require('mysql2');

// 创建数据库连接
const connection = mysql.createConnection({
  host: 'localhost',  // 数据库地址
  user: 'your_mysql_username', // 你的 MySQL 用户名
  password: 'your_mysql_password', // 你的 MySQL 密码
  database: 'my_webapp_db' // 要连接的数据库名
});

// 连接到数据库
connection.connect(err => {
  if (err) {
    console.error('数据库连接失败:', err.stack);
    return;
  }
  console.log('成功连接到数据库,连接 ID:', connection.threadId);

  // 在这里执行数据库操作...

  // 操作完成后关闭连接 (在实际应用中通常使用连接池)
  // connection.end();
});

// 注意:在实际应用中,不应将敏感信息直接写在代码中,应使用配置文件或环境变量。

执行 SQL 查询:

mysql2 支持回调和 Promise 两种方式执行查询。推荐使用 Promise 方式,因为它与 async/await 配合更优雅。

Promise 方式:

javascript 复制代码
// query_db.js
const mysql = require('mysql2/promise'); // 导入 Promise 版本的驱动

async function runQueries() {
  let connection;
  try {
    // 建立连接
    connection = await mysql.createConnection({
      host: 'localhost',
      user: 'your_mysql_username',
      password: 'your_mysql_password',
      database: 'my_webapp_db'
    });
    console.log('成功连接到数据库');

    // 执行 SELECT 查询
    const [rows, fields] = await connection.execute('SELECT * FROM users');
    console.log('查询结果:', rows); // rows 是一个包含查询结果的数组

    // 执行带参数的查询 (使用占位符 ?)
    const userId = 1;
    const [userRows] = await connection.execute('SELECT * FROM users WHERE id = ?', [userId]);
    console.log(`查询用户 ID ${userId}:`, userRows[0]); // 获取第一行结果

    // 执行 INSERT 查询
    const newUser = { username: 'charlie', email: 'charlie@example.com' };
    const [insertResult] = await connection.execute('INSERT INTO users (username, email) VALUES (?, ?)', [newUser.username, newUser.email]);
    console.log('插入结果:', insertResult);
    console.log('新用户 ID:', insertResult.insertId); // 获取新插入记录的 ID

  } catch (err) {
    console.error('数据库操作出错:', err);
  } finally {
    // 确保连接关闭
    if (connection) {
      await connection.end();
      console.log('数据库连接已关闭');
    }
  }
}

runQueries();

// 运行这个文件: node query_db.js

connection.execute() 方法返回一个 Promise, resolved 后得到一个数组,第一个元素是查询结果(对于 SELECT 是行数据,对于 INSERT/UPDATE/DELETE 是操作影响的信息),第二个元素是字段信息(通常不常用)。

连接池 (Connection Pool):

反复创建和关闭数据库连接是有开销的。在高并发场景下,为每个请求都创建新连接会导致性能问题。连接池是一组预先创建好的数据库连接,当需要执行数据库操作时,从池中获取一个连接;操作完成后,将连接归还给池,而不是关闭。这就像仓库门口有一个服务台,提前准备好了一些推车(连接),需要搬东西时直接领用推车,用完归还,而不是每次都去制造一个新推车。

在 Node.js 应用中,尤其是在 Express 或 NestJS 应用中,强烈推荐使用连接池。

javascript 复制代码
// pool_db.js
const mysql = require('mysql2/promise');

// 创建连接池
const pool = mysql.createPool({
  host: 'localhost',
  user: 'your_mysql_username',
  password: 'your_mysql_password',
  database: 'my_webapp_db',
  waitForConnections: true, // 如果连接都忙,等待连接可用
  connectionLimit: 10,     // 池中最大连接数
  queueLimit: 0          // 连接队列最大长度,0 表示无限制
});

async function getUserById(userId) {
  let connection;
  try {
    // 从连接池获取一个连接
    connection = await pool.getConnection();
    console.log(`连接 ID ${connection.threadId} 从连接池获取`);

    const [rows] = await connection.execute('SELECT * FROM users WHERE id = ?', [userId]);

    return rows[0]; // 返回第一个用户
  } catch (err) {
    console.error('获取用户出错:', err);
    throw err; // 抛出错误以便上层处理
  } finally {
    // 确保连接归还给连接池
    if (connection) {
      connection.release();
      console.log(`连接 ID ${connection.threadId} 归还给连接池`);
    }
  }
}

// 调用函数获取用户
async function main() {
    const user = await getUserById(2);
    console.log('查找到的用户:', user);

    // 当应用关闭时,关闭连接池 (在 Express/NestJS 应用退出时执行)
    // await pool.end();
    // console.log('连接池已关闭');
}

main();

// 运行这个文件: node pool_db.js

小结: 使用数据库驱动程序(如 mysql2)是 Node.js 连接和操作 MySQL 的方式。Promise API 结合 async/await 使得异步数据库操作更易读。连接池是管理数据库连接、提高应用性能的关键,尤其在处理并发请求时。

练习:

  1. 在你之前的 Node.js 项目(非 Express/NestJS)中安装 mysql2。
  2. 使用 Promise 方式编写一个脚本,连接到你的 my_bookstore_db 数据库。
  3. 执行一个 SELECT * FROM books 查询,并将所有书籍信息打印到控制台。
  4. 编写一个函数,接收书籍 ID 和新的出版年份作为参数,使用 UPDATE 语句更新指定书籍的出版年份。在脚本中调用该函数并测试。
  5. (进阶)修改你的脚本,使用连接池来执行查询。
相关推荐
太理摆烂哥7 分钟前
MySQL表的操作
数据库
lbb 小魔仙9 分钟前
时序数据库是什么?2026 年五款工业时序数据库横评与场景解析
数据库·时序数据库
零基础12313 分钟前
权限管理怎么做?从“资格”与“空间”双维度设计一套可落地的权限体系
java·服务器·数据库
小小龙学IT35 分钟前
PostgreSQL 服务端机制与 SQL 实战深度解析:从 MVCC 到查询优化器
数据库·sql·postgresql
l1t41 分钟前
DeepSeek总结的DuckDB 从 JSON 字符串到类型化列
数据库·sql·json
codeejun1 小时前
每日一Go·MySQL-7、MySQL 核心原理全景图谱
开发语言·mysql·golang
Raas1001 小时前
AI网关能做调用审计吗?MAI Gateway(魔芋企业级AI网关)实战能力深度解读
java·服务器·网络·数据库·gateway·prompt·企业级产品
foolishlee1 小时前
openGauss同步提交
数据库
minebmw71 小时前
第 04 讲 深入浅出索引(上):B+树索引的数据结构与查询过程
mysql
bksczm1 小时前
MySQL进阶篇之备份(下半篇)
数据库·mysql