Node.js 连接 MySQL

以下是关于如何使用 Node.js 连接 MySQL 数据库的中文讲解,内容涵盖环境准备、安装依赖、连接数据库、执行基本 CRUD 操作以及注意事项,帮助你快速上手 Node.js 与 MySQL 的结合开发。


1. 为什么使用 Node.js 连接 MySQL?

Node.js 是一个高效的 JavaScript 运行时,适合构建高并发、I/O 密集型应用,而 MySQL 是一种广泛使用的关系型数据库,适合存储结构化数据。结合两者可以实现:

  • 高效数据处理:Node.js 的异步非阻塞特性与 MySQL 的数据存储能力结合,适合 Web 应用、API 服务等场景。
  • 灵活开发:通过 Node.js 操作 MySQL,可以轻松实现数据的增删改查(CRUD)操作。
  • 广泛应用:许多 Web 应用(如博客、电商、后台管理系统)都依赖 Node.js 和 MySQL。

2. 环境准备

在开始之前,确保以下环境已配置好:

  1. Node.js:已安装 Node.js(建议版本 12 或以上)。验证:
   node --version
   npm --version
  1. MySQL:已安装 MySQL 服务器(社区版或企业版均可),并启动 MySQL 服务。验证:
   mysql --version
  1. 数据库和表:创建一个测试数据库(如 test_db)和表(如 users),用于后续操作。
    示例 SQL:
   CREATE DATABASE test_db;
   USE test_db;
   CREATE TABLE users (
       id INT AUTO_INCREMENT PRIMARY KEY,
       name VARCHAR(255) NOT NULL,
       email VARCHAR(255) NOT NULL
   );

3. 安装 MySQL 驱动

Node.js 通过 mysql2 模块连接 MySQL,mysql2 是目前推荐的 MySQL 驱动,支持 Promise 和回调两种方式,性能优于旧的 mysql 模块。

安装 mysql2

在项目目录下运行:

npm install mysql2

项目结构示例:

project/
├── index.js
├── package.json
├── node_modules/

4. 连接 MySQL 数据库

以下是一个简单的示例,展示如何使用 mysql2 连接 MySQL 数据库。

示例代码(index.js):

const mysql = require('mysql2');

// 创建数据库连接配置
const connection = mysql.createConnection({
  host: 'localhost', // MySQL 服务器地址
  user: 'root',      // MySQL 用户名
  password: 'your_password', // MySQL 密码
  database: 'test_db' // 数据库名称
});

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

// 关闭连接(通常在程序结束时)
connection.end();

运行代码:

node index.js

输出:

连接成功,连接 ID: 12345

说明:

  • 配置参数
  • host:MySQL 服务器地址,通常为 localhost(本地)或远程服务器 IP。
  • user:MySQL 用户名,默认为 root
  • password:MySQL 密码,替换为你的实际密码。
  • database:要连接的数据库名称。
  • 错误处理:使用回调函数检查连接是否成功。
  • 连接关闭connection.end() 用于在操作完成后关闭连接,避免资源泄漏。

5. 执行 CRUD 操作

以下展示如何使用 mysql2 进行基本的增删改查操作。

5.1 创建(Create) – 插入数据

const mysql = require('mysql2');

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'your_password',
  database: 'test_db'
});

// 插入数据
const sql = 'INSERT INTO users (name, email) VALUES (?, ?)';
const values = ['张三', 'zhangsan@example.com'];

connection.query(sql, values, (err, results) => {
  if (err) {
    console.error('插入失败:', err);
    return;
  }
  console.log('插入成功:', results);
  connection.end();
});

输出

插入成功: ResultSetHeader {
  fieldCount: 0,
  affectedRows: 1,
  insertId: 1,
  ...
}

说明

  • 使用 ? 占位符防止 SQL 注入,values 数组的值会按顺序替换占位符。
  • results 包含插入操作的元信息,如 affectedRows(影响的行数)和 insertId(新插入记录的 ID)。

5.2 读取(Read) – 查询数据

const mysql = require('mysql2');

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'your_password',
  database: 'test_db'
});

// 查询数据
const sql = 'SELECT * FROM users';

connection.query(sql, (err, results) => {
  if (err) {
    console.error('查询失败:', err);
    return;
  }
  console.log('查询结果:', results);
  connection.end();
});

输出

查询结果: [
  { id: 1, name: '张三', email: 'zhangsan@example.com' }
]

说明

  • results 是一个数组,包含查询到的所有记录。
  • 如果需要特定条件查询,可使用 WHERE,如 SELECT * FROM users WHERE id = ?

5.3 更新(Update) – 修改数据

const mysql = require('mysql2');

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'your_password',
  database: 'test_db'
});

// 更新数据
const sql = 'UPDATE users SET email = ? WHERE name = ?';
const values = ['zhangsan_new@example.com', '张三'];

connection.query(sql, values, (err, results) => {
  if (err) {
    console.error('更新失败:', err);
    return;
  }
  console.log('更新成功:', results.affectedRows, '条记录被更新');
  connection.end();
});

输出

更新成功: 1 条记录被更新

5.4 删除(Delete) – 删除数据

const mysql = require('mysql2');

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'your_password',
  database: 'test_db'
});

// 删除数据
const sql = 'DELETE FROM users WHERE id = ?';
const values = [1];

connection.query(sql, values, (err, results) => {
  if (err) {
    console.error('删除失败:', err);
    return;
  }
  console.log('删除成功:', results.affectedRows, '条记录被删除');
  connection.end();
});

输出

删除成功: 1 条记录被删除

6. 使用 Promise 方式(推荐)

mysql2 支持 Promise API,使用 async/await 语法可以让代码更简洁、更易读。

示例:使用 Promise 进行 CRUD

const mysql = require('mysql2/promise'); // 使用 mysql2/promise

async function main() {
  // 创建连接
  const connection = await mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'your_password',
    database: 'test_db'
  });

  try {
    // 插入
    await connection.execute('INSERT INTO users (name, email) VALUES (?, ?)', ['李四', 'lisi@example.com']);
    console.log('插入成功');

    // 查询
    const [rows] = await connection.execute('SELECT * FROM users');
    console.log('查询结果:', rows);

    // 更新
    await connection.execute('UPDATE users SET email = ? WHERE name = ?', ['lisi_new@example.com', '李四']);
    console.log('更新成功');

    // 删除
    await connection.execute('DELETE FROM users WHERE name = ?', ['李四']);
    console.log('删除成功');
  } catch (err) {
    console.error('操作失败:', err);
  } finally {
    // 关闭连接
    await connection.end();
  }
}

main();

输出

插入成功
查询结果: [ { id: 2, name: '李四', email: 'lisi@example.com' } ]
更新成功
删除成功

说明

  • 使用 mysql2/promise 导入 Promise 版本的 mysql2
  • connection.executeconnection.query 更安全,返回 [rows, fields] 格式。
  • 使用 try/catch 捕获异步错误。
  • 确保在 finally 中关闭连接。

7. 使用连接池(生产环境推荐)

在高并发场景下,频繁创建和关闭连接会影响性能。使用连接池可以复用数据库连接,提高效率。

示例:使用连接池

const mysql = require('mysql2/promise');

// 创建连接池
const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  password: 'your_password',
  database: 'test_db',
  waitForConnections: true, // 是否等待空闲连接
  connectionLimit: 10,     // 最大连接数
  queueLimit: 0            // 排队请求数(0 表示无限制)
});

async function main() {
  try {
    // 从连接池获取连接
    const connection = await pool.getConnection();

    // 查询
    const [rows] = await connection.execute('SELECT * FROM users');
    console.log('查询结果:', rows);

    // 释放连接回连接池
    connection.release();
  } catch (err) {
    console.error('操作失败:', err);
  } finally {
    // 关闭连接池
    await pool.end();
  }
}

main();

说明

  • createPool 创建一个连接池,管理多个连接。
  • getConnection 从池中获取一个连接,使用后通过 release 归还。
  • connectionLimit 控制最大连接数,根据服务器性能调整。
  • 适合高并发场景,如 Web 服务器。

8. 注意事项

  1. 防止 SQL 注入
  • 始终使用 ? 占位符或参数化查询(如 connection.execute),避免直接拼接 SQL 字符串。
  • 错误示例:
    javascript const sql = `SELECT * FROM users WHERE name = '${name}'`; // 不安全,易受 SQL 注入攻击
  1. 错误处理
  • 检查连接错误、查询错误(如表不存在、权限不足)。
  • 使用 try/catch 或回调函数中的 err 参数处理错误。
  1. 连接管理
  • 单次操作后关闭连接(connection.end())。
  • 高并发场景使用连接池(createPool)。
  1. 性能优化
  • 索引数据库表以提高查询性能。
  • 限制查询返回的行数(如 LIMIT 10)。
  • 使用连接池避免频繁建立连接。
  1. 安全性
  • 不要在代码中硬编码数据库密码,建议使用环境变量(如 process.env.DB_PASSWORD)。
  • 示例(使用 dotenv):
    bash npm install dotenv
    .env 文件:
    DB_HOST=localhost DB_USER=root DB_PASSWORD=your_password DB_NAME=test_db
    代码:
    javascript require('dotenv').config(); const connection = mysql.createConnection({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME });
  1. MySQL 配置
  • 确保 MySQL 服务正在运行。
  • 检查用户权限(如 root 是否有访问 test_db 的权限)。
  • 远程连接需配置 MySQL 允许远程访问(修改 bind-address 或授予用户权限)。

9. 实际案例:Express + MySQL

以下是一个结合 Express 和 MySQL 的简单 REST API 示例。

示例代码(app.js):

const express = require('express');
const mysql = require('mysql2/promise');

const app = express();
app.use(express.json());

// 创建连接池
const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  password: 'your_password',
  database: 'test_db',
  connectionLimit: 10
});

// 获取所有用户
app.get('/users', async (req, res) => {
  try {
    const [rows] = await pool.execute('SELECT * FROM users');
    res.json(rows);
  } catch (err) {
    res.status(500).json({ error: '查询失败' });
  }
});

// 添加用户
app.post('/users', async (req, res) => {
  const { name, email } = req.body;
  try {
    await pool.execute('INSERT INTO users (name, email) VALUES (?, ?)', [name, email]);
    res.status(201).json({ message: '用户添加成功' });
  } catch (err) {
    res.status(500).json({ error: '添加失败' });
  }
});

app.listen(3000, () => {
  console.log('服务器运行在 http://localhost:3000');
});

测试 API:

  1. 运行:node app.js
  2. 使用 curl 或 Postman 测试:
  • 获取用户:curl http://localhost:3000/users
  • 添加用户:curl -X POST -H "Content-Type: application/json" -d '{"name":"王五","email":"wangwu@example.com"}' http://localhost:3000/users

10. 总结

  • 模块选择:使用 mysql2 模块,支持回调和 Promise,推荐 Promise 方式以简化异步代码。
  • 连接方式:单次连接适合简单脚本,连接池适合高并发场景。
  • 安全与性能:使用参数化查询防止 SQL 注入,优化数据库索引和连接池配置。
  • 实际应用:结合 Express 等框架,轻松构建 REST API 或 Web 应用。

如果你需要更复杂的示例(如事务处理、分页查询)或有其他问题,请随时告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注