Node.js 连接 MySQL(深入浅出)

Node.js 连接 MySQL:从零开始构建数据库交互能力

你有没有想过,为什么很多网站能实时显示用户信息、订单状态或文章评论?背后的关键之一,就是数据库的支撑。而 Node.js 作为现代后端开发的主流选择,与 MySQL 的结合,正是构建动态网站的基石。

今天我们就来聊聊如何用 Node.js 连接 MySQL 数据库。别担心,即使你是编程初学者,只要跟着一步步来,也能轻松掌握这项核心技能。我们不会讲太多理论,而是用真实代码和场景,带你从“连不上”到“稳稳地查数据”。


为什么选择 Node.js 与 MySQL 的组合?

在开始之前,先理解一下这对“黄金搭档”为什么受欢迎。

Node.js 是基于 Chrome V8 引擎的 JavaScript 运行环境,它最大的特点是“非阻塞 I/O”,这意味着它可以高效处理大量并发请求,特别适合 Web 服务、API 接口等场景。

而 MySQL 是最流行的开源关系型数据库之一,结构清晰、稳定可靠,适合存储用户数据、商品信息、日志记录等结构化内容。

把它们放在一起,就像把“高速路”(Node.js)和“仓库”(MySQL)连接起来:前端发来的请求,通过 Node.js 快速处理,然后去 MySQL 仓库里找数据,再返回给用户。整个过程流畅又高效。


安装 MySQL 与准备数据库环境

在写代码之前,你得先有一个 MySQL 数据库可用。如果你还没装,可以按以下步骤操作。

安装 MySQL 服务(以 macOS 为例)

打开终端,执行以下命令:

brew install mysql

brew services start mysql

注意:如果你用的是 Windows 或 Linux,建议使用官方安装包或包管理器(如 apt、yum)安装 MySQL 服务。

登录 MySQL 并创建数据库

安装完成后,进入 MySQL 命令行:

mysql -u root -p

输入密码后,进入数据库命令行界面。接下来创建一个名为 myapp 的数据库:

-- 创建数据库
CREATE DATABASE myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 使用该数据库
USE myapp;

-- 创建一个用户表
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

✅ 小贴士:utf8mb4 是 MySQL 中支持 emoji 的编码,推荐使用。AUTO_INCREMENT 表示自增主键,就像给每条记录分配一个唯一的“身份证号”。


使用 npm 安装 MySQL 驱动

Node.js 本身不支持直接连接 MySQL,需要借助第三方驱动。最常用的驱动是 mysql2,它比旧版 mysql 更快、更稳定。

在项目根目录下,初始化项目并安装驱动:

npm init -y

npm install mysql2

📌 为什么用 mysql2?它支持 Promise、流式读取、预编译语句等现代特性,代码更简洁,性能更好。


编写连接代码:Node.js 连接 MySQL 的第一步

现在我们来写一段代码,实现 Node.js 与 MySQL 的连接。

创建一个文件 db.js,内容如下:

// db.js
const mysql = require('mysql2');

// 创建连接池(推荐方式,提高性能)
const pool = mysql.createPool({
  host: 'localhost',           // 数据库地址
  user: 'root',                // 用户名
  password: 'your_password',   // 替换为你的实际密码
  database: 'myapp',           // 要连接的数据库名
  port: 3306,                  // MySQL 默认端口
  waitForConnections: true,    // 是否等待连接
  connectionLimit: 10,         // 最大连接数
  queueLimit: 0                // 连接队列限制,0 表示无限制
});

// 将 pool 转为 Promise 风格,方便使用 async/await
const promisePool = pool.promise();

// 导出连接池对象,供其他模块使用
module.exports = promisePool;

📝 注释说明:

  • createPool 创建连接池,避免频繁创建/销毁连接,提升性能。
  • promise() 方法将回调风格转为 Promise 风格,让代码更清晰。
  • password 请替换为你自己的 MySQL 密码,别写死在代码里,生产环境建议用环境变量。

实际操作:插入与查询数据

现在连接已建立,我们来尝试插入和查询数据。

创建一个 user.js 文件,实现用户管理功能:

// user.js
const db = require('./db');

// 添加新用户
async function createUser(name, email) {
  try {
    // 使用 SQL 插入语句,参数用 ? 占位符,防止 SQL 注入
    const [result] = await db.execute(
      'INSERT INTO users (name, email) VALUES (?, ?)',
      [name, email]
    );

    console.log('用户创建成功,ID:', result.insertId);
    return result.insertId;
  } catch (err) {
    console.error('插入失败:', err.message);
    throw err;
  }
}

// 查询所有用户
async function getAllUsers() {
  try {
    const [rows] = await db.execute('SELECT id, name, email, created_at FROM users');
    console.log('所有用户:', rows);
    return rows;
  } catch (err) {
    console.error('查询失败:', err.message);
    throw err;
  }
}

// 按 ID 查询用户
async function getUserById(id) {
  try {
    const [rows] = await db.execute(
      'SELECT id, name, email, created_at FROM users WHERE id = ?',
      [id]
    );

    if (rows.length === 0) {
      console.log('未找到用户');
      return null;
    }

    console.log('找到用户:', rows[0]);
    return rows[0];
  } catch (err) {
    console.error('查询失败:', err.message);
    throw err;
  }
}

// 导出函数
module.exports = { createUser, getAllUsers, getUserById };

🔍 重点说明:

  • 使用 ? 占位符是安全做法,能有效防止 SQL 注入攻击。
  • await db.execute() 返回的是一个数组,第一个元素是结果,第二个是元数据。
  • rows.length === 0 是判断查询结果为空的常见写法。

运行测试:验证连接是否成功

创建 index.js 文件,作为入口文件:

// index.js
const { createUser, getAllUsers, getUserById } = require('./user');

async function main() {
  try {
    // 插入两个测试用户
    await createUser('张三', 'zhangsan@example.com');
    await createUser('李四', 'lisi@example.com');

    // 查询所有用户
    const users = await getAllUsers();

    // 查询单个用户
    const user = await getUserById(1);

    console.log('✅ 所有操作完成,Node.js 连接 MySQL 成功!');
  } catch (err) {
    console.error('❌ 运行出错:', err.message);
  }
}

main();

在终端运行:

node index.js

如果看到类似输出:

用户创建成功,ID: 1
用户创建成功,ID: 2
所有用户: [ { id: 1, name: '张三', email: 'zhangsan@example.com', created_at: 2025-04-05T10:00:00.000Z }, ... ]
找到用户: { id: 1, name: '张三', email: 'zhangsan@example.com', created_at: 2025-04-05T10:00:00.000Z }
✅ 所有操作完成,Node.js 连接 MySQL 成功!

恭喜你,已经成功实现了 Node.js 连接 MySQL 的完整流程!


常见问题与最佳实践

在实际项目中,我们常会遇到一些问题。下面列出几个关键点:

1. 连接超时或拒绝连接?

  • 检查 MySQL 是否正在运行:brew services list | grep mysql
  • 检查 host 是否正确(localhost 或 127.0.0.1)
  • 确认用户名和密码无误(注意区分大小写)

2. 如何避免密码明文暴露?

使用 .env 文件管理敏感信息。安装 dotenv

npm install dotenv

创建 .env 文件:

DB_HOST=localhost
DB_USER=root
DB_PASSWORD=your_secure_password
DB_NAME=myapp

修改 db.js

require('dotenv').config();

const pool = mysql.createPool({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  port: 3306,
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
});

✅ 这样做更安全,也方便多环境部署。

3. 使用事务处理多步操作

当需要“要么全成功,要么全失败”时,比如转账,就要用事务:

async function transferMoney(fromId, toId, amount) {
  const connection = await db.getConnection();
  try {
    await connection.beginTransaction();

    // 扣款
    await connection.execute(
      'UPDATE users SET balance = balance - ? WHERE id = ?',
      [amount, fromId]
    );

    // 加款
    await connection.execute(
      'UPDATE users SET balance = balance + ? WHERE id = ?',
      [amount, toId]
    );

    await connection.commit();
    console.log('转账成功');
  } catch (err) {
    await connection.rollback();
    console.error('转账失败,已回滚:', err.message);
    throw err;
  } finally {
    connection.release();
  }
}

🧠 事务就像“银行转账”:两笔操作必须同时成功,否则全部撤销。


结语

今天我们从零开始,一步步完成了 Node.js 连接 MySQL 的全过程:环境搭建、驱动安装、连接配置、数据操作,再到生产级优化建议。

你已经掌握了这项核心技能,接下来可以尝试:

  • 用 Express 搭建 REST API
  • 将数据返回给前端(如 Vue 3.0、React)
  • 实现用户登录、注册功能

Node.js 连接 MySQL 不是“高阶技巧”,而是每个全栈开发者都该掌握的基础能力。只要动手实践,你也能写出稳定、高效的后端服务。

别停下脚步,下一站,就是你的第一个完整项目!