上一篇
JavaScript中,通常通过Node.js搭配相应驱动(如mysql、pg等)来连接数据库,先安装依赖包,再编写代码建立连接。
是关于如何使用JavaScript连接数据库的详细介绍:
核心原理
由于浏览器端的JavaScript受安全限制无法直接访问数据库,因此实际开发中通常基于Node.js环境实现后端数据库交互,Node.js作为JavaScript的服务器端运行环境,可通过加载不同数据库驱动或ORM工具完成与MySQL、PostgreSQL、MongoDB等主流数据库的通信。
主流方案对比
| 类型 | 代表库/工具 | 适用场景 | 优势特点 |
|---|---|---|---|
| 原生驱动 | mysql2, pg, mongodb |
精细化控制SQL语句 | 高性能、低延迟;适合复杂事务处理 |
| ORM框架 | Sequelize, TypeORM | 结构化项目开发 | 模型映射直观,自动生成迁移脚本;支持关联查询 |
| ODM工具 | Mongoose | NoSQL文档型数据库 | 简化Schema定义,内置数据校验功能 |
| 连接池管理 | mysql.createPool |
高并发场景 | 复用连接实例减少开销,提升吞吐量 |
具体实现步骤(以MySQL为例)
环境准备与依赖安装
npm install express mysql2 dotenv # Express用于构建API,mysql2为优化版驱动,dotenv管理环境变量
创建.env文件存储敏感信息:
DB_HOST=localhost DB_USER=root DB_PASS=your_password DB_NAME=test_db
基础连接代码示例
const mysql = require('mysql2'); // 使用Promise支持的版本
const connection = mysql.createConnection({
host: process.env.DB_HOST, // 从环境变量读取配置
user: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
waitForConnections: true // 强制等待连接建立成功
});
// 异步错误处理模式
connection.connect(err => {
if (err) throw new Error(`数据库连接失败: ${err.stack}`);
console.log(`成功连接到ID为${connection.threadId}的数据库线程`);
});
// 执行查询并解析结果集
connection.execute('SELECT FROM users WHERE age > ?', [18], (err, [rows]) => {
if (err) return console.error('查询异常:', err);
rows.forEach(user => console.log(`用户${user.id}: ${user.name}`));
});
// 推荐使用async/await语法糖
async function getActiveUsers() {
const [results] = await connection.promise().query('SELECT FROM users LIMIT 5');
return results;
}
进阶优化策略
- 连接池配置(应对高并发):
const pool = mysql.createPool({ connectionLimit: 10, // 同时保持的最大连接数 queueLimit: 0, // 允许等待中的请求无限增长(生产环境建议设为合理值) waitForConnections: true, // 确保始终有可用连接时才执行新请求 ...process.env // 合并环境变量中的其他参数 }); - 事务完整性保障:
const promiseConn = connection.promise(); await promiseConn.beginTransaction(); try { await promiseConn.query('UPDATE account SET balance -= ? WHERE id = ?', [amount, senderId]); await promiseConn.query('UPDATE account SET balance += ? WHERE id = ?', [amount, receiverId]); await promiseConn.commit(); } catch (e) { await promiseConn.rollback(); // 出错时回滚所有已执行操作 throw e; }
ORM框架实战(以Sequelize为例)
初始化及模型定义
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASS, {
host: process.env.DB_HOST,
dialect: 'mysql', // 根据实际使用的数据库调整类型标识符
logging: false // 关闭默认的SQL日志输出
});
// 定义用户模型(自动对应users表)
const User = sequelize.define('User', {
username: { type: DataTypes.STRING, unique: true },
email: { type: DataTypes.STRING, validate: { isEmail: true } }, // 内置验证规则
createdAt: { type: DataTypes.DATE, defaultValue: Sequelize.NOW }
});
// 同步数据库结构到最新模型状态
await sequelize.sync({ alter: true }); // alter选项会修改现有表而非重建
CRUD操作演示
// 创建新记录
const jane = await User.create({ username: 'janedoe', email: 'jane@example.com' });
// 组合条件查询
const engineers = await User.findAll({ where: { role: 'engineer' }, order: [['salary', 'DESC']] });
// 更新特定字段
await User.update({ status: 'active' }, { where: { lastLoginDate: { [Op.gt]: new Date().setDate(new Date().getDate() 30) } } });
// 物理删除+软删除双模式支持
await User.destroy({ where: { id: expiredUserId }, force: true }); // force参数强制硬删除
常见问题解决方案
| 症状 | 可能原因 | 修复方案 |
|---|---|---|
| ECONNREFUSED错误 | 防火墙阻止端口通信 | 检查服务器防火墙设置,确认3306/27017等端口已开放给Node进程 |
| Too many connections报错 | 未正确释放数据库连接 | 确保每次请求结束后调用connection.release()或使用连接池自动回收机制 |
| 中文字符显示乱码 | 编码格式不匹配 | 在连接配置中添加charset: 'utf8mb4'参数支持完整Unicode字符集 |
| TIMEZONE偏移导致时间错误 | 时区设置不一致 | 统一使用UTC时间存储,前端展示时根据用户本地时区转换 |
| SQL注入破绽风险 | 直接拼接用户输入参数 | 始终使用参数化查询(如占位符),避免使用${variable}形式的字符串插值 |
相关问答FAQs
Q1: JavaScript能否直接在浏览器中连接数据库?
A: 出于安全考虑,浏览器端的JavaScript严禁直接访问数据库,所有数据库操作都必须通过服务端语言(如Node.js)中转实现,若需前后端分离架构,建议使用RESTful API作为通信桥梁。
Q2: ORM和原生驱动哪个性能更好?
A: 原生驱动因减少中间层转换通常具有更高吞吐量,但ORM在开发效率、可维护性和安全性方面优势明显,对于简单CRUD场景推荐使用ORM;而在需要极致性能的关键路径(如高频交易系统),则更适合用原生
