Node.js 作为一种基于 Chrome V8 引擎的 JavaScript 运行时,因其事件驱动、非阻塞 I/O 的特性,在构建高性能服务器端应用方面备受青睐,在实际开发中,数据库操作是不可或缺的一环,本文将详细介绍 Node.js 如何使用数据库,包括常见数据库类型、连接方式、查询操作以及最佳实践等内容。

选择合适的数据库
Node.js 可以与多种数据库协同工作,主要分为关系型数据库和非关系型数据库两大类,关系型数据库如 MySQL、PostgreSQL、SQLite 等,采用表格结构存储数据,支持 SQL 查询,适用于需要强事务性和复杂查询的场景,非关系型数据库如 MongoDB(文档型)、Redis(键值型)、Neo4j(图型)等,数据结构灵活,扩展性强,适合高并发、大数据量的应用场景,开发者需根据业务需求(如数据结构、一致性要求、读写性能等)选择合适的数据库类型。
安装数据库驱动或 ORM
连接数据库前,需要安装相应的驱动程序或对象关系映射(ORM)工具,以 MySQL 为例,可以使用官方的 mysql 包或 mysql2 包(后者性能更优,支持 Promise);对于 MongoDB,官方提供了 mongodb 驱动,而 Mongoose 是一个流行的 ORM 框架,提供了数据建模和验证功能,安装方式通常通过 npm(Node.js 包管理器)完成,npm install mysql2 或 npm install mongoose,ORM 工具能将数据库操作转化为 JavaScript 对象方法,简化代码并提高可维护性,尤其适合复杂的数据关系处理。
建立数据库连接
数据库连接是操作数据库的前提,以 MySQL 为例,首先导入驱动模块,然后创建连接池(Connection Pool)以提升性能,连接池可以复用连接,避免频繁创建和销毁连接带来的开销,示例代码如下:
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'test_db',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
module.exports = pool;
对于 MongoDB,使用 Mongoose 时,需先连接到 MongoDB 服务:

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/test_db', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const db = mongoose.connection;
db.on('error', console.error.bind(console, '连接错误:'));
db.once('open', () => {
console.log('成功连接到 MongoDB');
});
执行数据库操作
建立连接后,即可执行增删改查(CRUD)操作,以 MySQL 为例,使用 pool.query() 方法执行 SQL 语句,该方法支持 Promise,便于异步处理:
// 查询数据
async function getUsers() {
try {
const [rows] = await pool.query('SELECT * FROM users');
console.log(rows);
} catch (err) {
console.error('查询错误:', err);
}
}
// 插入数据
async function addUser(name, email) {
try {
const [result] = await pool.query(
'INSERT INTO users (name, email) VALUES (?, ?)',
[name, email]
);
console.log('插入成功,ID:', result.insertId);
} catch (err) {
console.error('插入错误:', err);
}
}
对于 MongoDB,使用 Mongoose 定义模型后,可通过模型实例操作数据:
const userSchema = new mongoose.Schema({
name: String,
email: { type: String, unique: true }
});
const User = mongoose.model('User', userSchema);
// 创建文档
async function createUser(name, email) {
try {
const user = new User({ name, email });
await user.save();
console.log('用户创建成功:', user);
} catch (err) {
console.error('创建错误:', err);
}
}
// 查询文档
async function findUsers() {
try {
const users = await User.find({});
console.log(users);
} catch (err) {
console.error('查询错误:', err);
}
}
事务处理
在需要保证数据一致性的场景(如银行转账、订单创建等),需使用事务,MySQL 中可通过 pool.getConnection() 获取连接后,启动事务并执行多个 SQL 语句:
async function transferMoney(fromId, toId, amount) {
const connection = await pool.getConnection();
await connection.beginTransaction();
try {
await connection.query('UPDATE accounts SET balance = balance - ? WHERE id = ?', [amount, fromId]);
await connection.query('UPDATE accounts SET balance = balance + ? WHERE id = ?', [amount, toId]);
await connection.commit();
console.log('转账成功');
} catch (err) {
await connection.rollback();
console.error('转账失败:', err);
} finally {
connection.release();
}
}
最佳实践
- 使用连接池:避免频繁创建和销毁连接,提升性能。
- 参数化查询:防止 SQL 注入攻击,使用 占位符而非直接拼接 SQL。
- 错误处理:捕获数据库操作中的异常,避免程序崩溃。
- 异步处理:充分利用 Node.js 的异步特性,使用
async/await或 Promise 管理异步操作。 - ORM 优化:合理使用 ORM 的延迟加载、预加载等功能,避免 N+1 查询问题。
- 环境变量管理:将数据库连接信息(如密码、主机名)存储在环境变量中,而非硬编码在代码中。
相关问答 FAQs
Q1:Node.js 如何防止 SQL 注入?
A1:防止 SQL 注入的核心方法是使用参数化查询(Prepared Statements),在执行 SQL 语句时,将用户输入作为参数传递,而非直接拼接 SQL 字符串,使用 mysql2 包时,通过 占位符和数组参数传递值:pool.query('SELECT * FROM users WHERE name = ?', [userName]),ORM 工具(如 Sequelize、Mongoose)默认会对输入进行转义,能有效防止 SQL 注入。

Q2:Node.js 中如何处理数据库连接超时?
A2:数据库连接超时通常由网络问题或服务器负载过高导致,可通过以下方式解决:
- 调整连接池配置:增加
connectionLimit,设置acquireTimeout(获取连接超时时间)和timeout(查询超时时间)。 - 心跳机制:定期执行简单查询(如
SELECT 1)保持连接活跃,避免被数据库服务器断开。 - 重试逻辑:在连接失败时,采用指数退避算法(Exponential Backoff)进行重试。
- 监控与告警:实时监控数据库连接状态,及时发现并处理异常连接。