JavaScript中如何连接数据库
JavaScript作为一种广泛使用的编程语言,在前端和后端开发中都扮演着重要角色。很多开发者都会遇到一个常见的问题:JavaScript如何连接数据库?这个问题的答案取决于JavaScript的运行环境。在浏览器端,JavaScript出于安全考虑不能直接连接数据库,通常需要通过后端API间接操作。而在Node.js环境中,JavaScript可以直接通过数据库驱动来连接和操作各种数据库。
本文将从两个场景出发,详细介绍JavaScript连接数据库的常见方式,并提供完整的代码示例。
浏览器端JavaScript与数据库的交互
在浏览器中,JavaScript不能直接连接数据库(如MySQL、PostgreSQL等),因为这会暴露数据库的凭据和结构,带来严重的安全风险。浏览器端JavaScript通常通过HTTP请求与后端API通信,后端再负责与数据库交互。
这种方式的核心流程是:前端发送请求到后端接口,后端处理业务逻辑并查询数据库,最后将结果返回给前端。
下面是一个使用fetch API发送请求的示例:
// 浏览器端JavaScript通过API间接操作数据库
async function getUserData(userId) {
try {
const response = await fetch('/api/users/' + userId, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('网络请求失败,状态码:' + response.status);
}
const userData = await response.json();
console.log('获取到用户数据:', userData);
return userData;
} catch (error) {
console.error('获取用户数据失败:', error.message);
throw error;
}
}
// 调用函数获取用户数据
getUserData(123).then(data => {
// 处理返回的数据
document.getElementById('userName').textContent = data.name;
});上面的代码展示了浏览器端如何通过fetch API与后端交互。后端API(例如运行在Node.js上的Express服务)会负责实际的数据库查询操作,然后将结果以JSON格式返回给前端。
Node.js环境中连接数据库
在Node.js环境中,JavaScript可以直接连接数据库。Node.js提供了丰富的数据库驱动包,可以通过npm安装使用。下面介绍几种常见数据库的连接方式。
连接MySQL数据库
MySQL是目前最流行的关系型数据库之一。在Node.js中连接MySQL,通常使用mysql或mysql2包。下面是使用mysql2连接MySQL数据库的完整示例:
// 使用mysql2连接MySQL数据库
const mysql = require('mysql2');
// 创建数据库连接配置
const connectionConfig = {
host: 'localhost',
port: 3306,
user: 'root',
password: 'your_password',
database: 'your_database'
};
// 创建连接
const connection = mysql.createConnection(connectionConfig);
// 连接数据库
connection.connect((error) => {
if (error) {
console.error('数据库连接失败:', error.message);
return;
}
console.log('成功连接到MySQL数据库');
});
// 执行查询
connection.query('SELECT * FROM users WHERE id = ?', [1], (error, results) => {
if (error) {
console.error('查询失败:', error.message);
return;
}
console.log('查询结果:', results);
});
// 关闭连接
connection.end((error) => {
if (error) {
console.error('关闭连接失败:', error.message);
return;
}
console.log('数据库连接已关闭');
});上面的代码展示了最基本的连接方式。在实际项目中,直接使用单次连接的方式并不推荐,因为每次请求都创建和销毁连接会带来较大的性能开销。更好的做法是使用连接池来管理数据库连接。
使用连接池连接MySQL
连接池可以复用数据库连接,显著提升应用的性能和稳定性。下面是使用mysql2连接池的示例:
// 使用连接池管理MySQL连接
const mysql = require('mysql2');
// 创建连接池
const pool = mysql.createPool({
host: 'localhost',
port: 3306,
user: 'root',
password: 'your_password',
database: 'your_database',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
// 从连接池获取连接并执行查询
pool.getConnection((error, connection) => {
if (error) {
console.error('获取连接失败:', error.message);
return;
}
connection.query(
'SELECT id, name, email FROM users WHERE status = ?',
['active'],
(queryError, results) => {
// 释放连接回连接池
connection.release();
if (queryError) {
console.error('查询失败:', queryError.message);
return;
}
console.log('查询到' + results.length + '条活跃用户记录');
results.forEach(user => {
console.log('用户:' + user.name + ',邮箱:' + user.email);
});
}
);
});
// 使用Promise方式更简洁
const promisePool = pool.promise();
async function getActiveUsers() {
try {
const [rows, fields] = await promisePool.query(
'SELECT id, name, email FROM users WHERE status = ?',
['active']
);
console.log('使用Promise方式查询到' + rows.length + '条记录');
return rows;
} catch (error) {
console.error('查询失败:', error.message);
throw error;
}
}连接池可以显著减少连接建立和销毁的开销,同时通过限制最大连接数来防止数据库过载。上面的示例中同时展示了回调方式和Promise方式两种用法,Promise方式可以让代码更加简洁易读。
连接MongoDB数据库
MongoDB是最流行的NoSQL数据库之一,在Node.js中通常使用mongoose或官方的mongodb驱动程序来连接。下面是使用mongoose连接MongoDB的示例:
// 使用mongoose连接MongoDB数据库
const mongoose = require('mongoose');
// 定义数据库连接地址
const dbUri = 'mongodb://localhost:27017/your_database';
// 连接数据库
mongoose.connect(dbUri, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log('成功连接到MongoDB数据库');
})
.catch((error) => {
console.error('连接MongoDB失败:', error.message);
});
// 定义数据模型
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
email: {
type: String,
required: true,
unique: true,
lowercase: true
},
age: {
type: Number,
min: 0,
max: 150
},
createdAt: {
type: Date,
default: Date.now
}
});
// 创建模型
const User = mongoose.model('User', userSchema);
// 使用模型操作数据库
async function createUser(userData) {
try {
const newUser = new User(userData);
const savedUser = await newUser.save();
console.log('用户创建成功,ID:' + savedUser._id);
return savedUser;
} catch (error) {
console.error('创建用户失败:', error.message);
throw error;
}
}
async function findUsersByAge(minAge, maxAge) {
try {
const users = await User.find({
age: { $gte: minAge, $lte: maxAge }
}).select('name email age').sort({ age: 1 });
console.log('查找到' + users.length + '个用户');
return users;
} catch (error) {
console.error('查询用户失败:', error.message);
throw error;
}
}
// 调用示例
createUser({ name: '张三', email: 'zhangsan@ipipp.com', age: 28 });
findUsersByAge(20, 35).then(users => {
console.log('年龄在20-35之间的用户:', users);
});mongoose提供了Schema定义、数据验证、查询构建等丰富的功能,让MongoDB的操作更加便捷和安全。上面的示例中定义了用户模型,并演示了创建和查询数据的基本操作。
连接PostgreSQL数据库
PostgreSQL是功能强大的开源关系型数据库。在Node.js中,通常使用pg包来连接PostgreSQL。下面是一个连接示例:
// 使用pg连接PostgreSQL数据库
const { Pool } = require('pg');
// 创建连接池
const pool = new Pool({
host: 'localhost',
port: 5432,
user: 'postgres',
password: 'your_password',
database: 'your_database',
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000
});
// 监听连接池事件
pool.on('connect', () => {
console.log('新的数据库连接已建立');
});
pool.on('error', (error) => {
console.error('数据库连接池异常:', error.message);
});
// 执行查询
async function queryUsers(searchKeyword) {
const client = await pool.connect();
try {
const queryText = 'SELECT id, username, email, created_at FROM users WHERE username LIKE $1';
const result = await client.query(queryText, ['%' + searchKeyword + '%']);
console.log('查询到' + result.rowCount + '条记录');
return result.rows;
} catch (error) {
console.error('查询失败:', error.message);
throw error;
} finally {
// 释放客户端回连接池
client.release();
}
}
// 事务处理示例
async function transferFunds(fromUserId, toUserId, amount) {
const client = await pool.connect();
try {
// 开始事务
await client.query('BEGIN');
// 扣减转出用户余额
const deductResult = await client.query(
'UPDATE accounts SET balance = balance - $1 WHERE user_id = $2 AND balance >= $1 RETURNING balance',
[amount, fromUserId]
);
if (deductResult.rowCount === 0) {
throw new Error('余额不足或用户不存在');
}
// 增加转入用户余额
await client.query(
'UPDATE accounts SET balance = balance + $1 WHERE user_id = $2',
[amount, toUserId]
);
// 提交事务
await client.query('COMMIT');
console.log('转账成功,转出' + amount + '元');
return true;
} catch (error) {
// 回滚事务
await client.query('ROLLBACK');
console.error('转账失败:', error.message);
throw error;
} finally {
client.release();
}
}PostgreSQL的连接方式和MySQL类似,也推荐使用连接池来管理连接。上面的示例展示了基本的查询操作和事务处理,事务可以确保一系列数据库操作要么全部成功,要么全部失败,保证数据的一致性。
使用ORM框架简化数据库操作
直接使用数据库驱动编写SQL语句虽然灵活,但代码量较大且容易出错。ORM(Object-Relational Mapping)框架可以帮助开发者用面向对象的方式操作数据库,大大简化开发工作。在Node.js生态中,Sequelize是一个非常流行的ORM框架,支持MySQL、PostgreSQL、SQLite等多种数据库。
下面是一个使用Sequelize连接数据库的示例:
// 使用Sequelize ORM连接数据库
const { Sequelize, DataTypes, Op } = require('sequelize');
// 创建Sequelize实例
const sequelize = new Sequelize('your_database', 'root', 'your_password', {
host: 'localhost',
dialect: 'mysql', // 可选:'mysql' | 'postgres' | 'sqlite' | 'mariadb'
pool: {
max: 10,
min: 0,
acquire: 30000,
idle: 10000
},
logging: false // 关闭SQL日志
});
// 定义模型
const Product = sequelize.define('Product', {
name: {
type: DataTypes.STRING(100),
allowNull: false,
validate: {
notEmpty: true
}
},
price: {
type: DataTypes.DECIMAL(10, 2),
allowNull: false,
validate: {
min: 0
}
},
stock: {
type: DataTypes.INTEGER,
defaultValue: 0,
validate: {
min: 0
}
},
category: {
type: DataTypes.STRING(50),
allowNull: true
}
}, {
tableName: 'products',
timestamps: true, // 自动添加createdAt和updatedAt
underscored: true // 使用下划线命名规则
});
// 同步模型到数据库
async function syncDatabase() {
try {
await sequelize.sync({ alter: true });
console.log('数据库模型同步完成');
} catch (error) {
console.error('模型同步失败:', error.message);
}
}
// 使用模型进行CRUD操作
async function productOperations() {
// 创建商品
const newProduct = await Product.create({
name: '无线蓝牙耳机',
price: 199.99,
stock: 100,
category: '电子产品'
});
console.log('创建商品成功,ID:' + newProduct.id);
// 查询商品
const products = await Product.findAll({
where: {
price: {
[Op.between]: [100, 500]
},
stock: {
[Op.gt]: 0
}
},
order: [['price', 'ASC']],
limit: 10
});
console.log('价格在100-500之间且有库存的商品:' + products.length + '个');
// 更新商品
const [affectedCount] = await Product.update(
{ price: 179.99 },
{ where: { id: newProduct.id } }
);
console.log('更新了' + affectedCount + '条记录');
// 删除商品
const deletedCount = await Product.destroy({
where: { id: newProduct.id }
});
console.log('删除了' + deletedCount + '条记录');
}
// 关闭连接
async function closeConnection() {
await sequelize.close();
console.log('数据库连接已关闭');
}ORM框架最大的优势是让开发者可以用JavaScript对象的方式来操作数据库,而不需要直接编写SQL语句。Sequelize还提供了数据验证、关联查询、事务处理等高级功能,可以显著提高开发效率。
数据库连接的安全最佳实践
在编写数据库连接代码时,安全性是需要重点关注的问题。以下是一些重要的安全实践:
- 不要硬编码凭据:数据库的用户名、密码、主机地址等信息不应该直接写在代码中。应该使用环境变量或配置文件来管理这些敏感信息。
- 使用参数化查询:永远不要直接拼接SQL字符串,这会导致SQL注入攻击。上面示例中使用的问号占位符或$1占位符都是参数化查询的正确方式。
- 最小权限原则:为应用程序创建专门的数据库用户,只授予其所需的最小权限,不要使用root或管理员账户。
- 加密连接:在生产环境中,应该使用SSL/TLS加密数据库连接,防止数据在传输过程中被窃听。
- 设置连接超时:合理设置连接超时时间,避免因数据库不可用导致应用长时间挂起。
- 定期轮换密码:数据库密码应该定期更换,并避免使用简单密码。
下面是一个使用环境变量管理数据库配置的示例:
// 使用环境变量管理数据库配置
require('dotenv').config();
const mysql = require('mysql2/promise');
// 从环境变量读取数据库配置
const dbConfig = {
host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT, 10) || 3306,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
ssl: process.env.DB_SSL === 'true' ? {
rejectUnauthorized: true
} : undefined,
connectTimeout: parseInt(process.env.DB_TIMEOUT, 10) || 10000
};
// 验证必要配置是否存在
if (!dbConfig.user || !dbConfig.password || !dbConfig.database) {
console.error('数据库配置不完整,请检查环境变量');
process.exit(1);
}
// 创建连接池
const pool = mysql.createPool(dbConfig);
// 导出连接池供其他模块使用
module.exports = pool;使用环境变量管理配置可以让代码更安全、更灵活,不同的部署环境可以有不同的配置,而不需要修改代码。
JavaScript连接数据库的方式取决于运行环境。在浏览器端,需要通过后端API间接操作数据库。在Node.js环境中,可以直接使用数据库驱动或ORM框架来连接和操作各种数据库。选择哪种方式取决于项目的具体需求、团队的技术栈以及数据库的类型。
无论选择哪种方式,安全性都应该是首要考虑的因素。使用参数化查询、管理好数据库凭据、遵循最小权限原则,这些都是保障数据库安全的基础措施。同时,使用连接池和合理配置连接参数,可以有效提升应用的性能和稳定性。