第七部分:第二节 - 在 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. (进阶)修改你的脚本,使用连接池来执行查询。
相关推荐
蓝色猪猪侠33 分钟前
postgresql数据库的安装
数据库
敖云岚41 分钟前
【疑难解答】MySQL 报错 Public Key Retrieval is not allowed
数据库·mysql
用户47949283569151 小时前
你知道node背后的libuv是什么吗
node.js
小旺不正经1 小时前
Linux介绍及常用命令
linux·运维·数据库
焦糖码奇朵、2 小时前
移动通信网络建设-实验2:5G站点选型与设备部署
网络·数据库·人工智能·5g·信号处理·基带工程
l1t2 小时前
把ITPUB newkid先生编写的Oracle语法数独求解SQL改写成DuckDB
数据库·人工智能·sql·oracle·duckdb
ヾChen2 小时前
MySQL——增删改查操作
数据库·sql·物联网·学习·mysql
betazhou2 小时前
Oracle Goldengate 同步过程的同步用户权限设置
数据库·oracle·goldengate·ogg·goldengate授权
0和1的舞者2 小时前
《MySQL数据库进阶(九):数据库备份与恢复(二)》
数据库·mysql·oracle·程序员·策略模式·备份与恢复
稻香味秋天2 小时前
MySQL和DB2在SQL语法上的差异
数据库·sql