第七部分:第二节 - 在 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. (进阶)修改你的脚本,使用连接池来执行查询。
相关推荐
.Shu.1 小时前
Mysql InnoDB 底层架构设计、功能、原理、源码系列合集【五、InnoDB 高阶机制与实战调优】
数据库·mysql
辉长六加12 小时前
nodejs和vue安装步骤记录
前端·javascript·vue.js·npm·node.js
新法国菜3 小时前
MySql知识梳理之DDL语句
数据库·mysql
DarkAthena3 小时前
【GaussDB】全密态等值查询功能测试及全密态技术介绍
数据库·gaussdb
ShawnLeiLei4 小时前
2.3 Flink的核心概念解析
数据库·python·flink
石皮幼鸟5 小时前
数据完整性在所有场景下都很重要吗?
数据库·后端
大只鹅5 小时前
Centos7.9 Docker26容器化部署 MySql9.4 一主一从的同步复制部署
mysql·centos
叁沐6 小时前
MySQL 28 读写分离有哪些坑?
mysql
nightunderblackcat6 小时前
新手向:异步编程入门asyncio最佳实践
前端·数据库·python
DarkAthena6 小时前
【GaussDB】使用MySQL客户端连接到GaussDB的M-Compatibility数据库
数据库·mysql·gaussdb