Appearance
Node.js 数据库操作指南
目录
关系型数据库
MySQL
1. 基本连接
javascript
const mysql = require("mysql2/promise");
async function connectDB() {
const connection = await mysql.createConnection({
host: "localhost",
user: "root",
password: "password",
database: "test",
});
return connection;
}
// 使用连接池
const pool = mysql.createPool({
host: "localhost",
user: "root",
password: "password",
database: "test",
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0,
});
2. 基本操作
javascript
async function databaseOperations() {
const connection = await connectDB();
try {
// 创建表
await connection.execute(`
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
// 插入数据
const [result] = await connection.execute(
"INSERT INTO users (name, email) VALUES (?, ?)",
["John Doe", "john@example.com"]
);
console.log("Inserted ID:", result.insertId);
// 查询数据
const [rows] = await connection.execute(
"SELECT * FROM users WHERE id = ?",
[result.insertId]
);
console.log("User:", rows[0]);
// 更新数据
await connection.execute("UPDATE users SET name = ? WHERE id = ?", [
"John Smith",
result.insertId,
]);
// 删除数据
await connection.execute("DELETE FROM users WHERE id = ?", [
result.insertId,
]);
} catch (err) {
console.error("Error:", err);
} finally {
await connection.end();
}
}
3. 事务处理
javascript
async function transactionExample() {
const connection = await connectDB();
try {
await connection.beginTransaction();
await connection.execute(
"INSERT INTO accounts (user_id, balance) VALUES (?, ?)",
[1, 1000]
);
await connection.execute(
"UPDATE accounts SET balance = balance - ? WHERE user_id = ?",
[100, 1]
);
await connection.execute(
"UPDATE accounts SET balance = balance + ? WHERE user_id = ?",
[100, 2]
);
await connection.commit();
} catch (err) {
await connection.rollback();
throw err;
} finally {
await connection.end();
}
}
PostgreSQL
1. 基本连接
javascript
const { Pool } = require("pg");
const pool = new Pool({
user: "postgres",
host: "localhost",
database: "test",
password: "password",
port: 5432,
});
2. 基本操作
javascript
async function postgresOperations() {
const client = await pool.connect();
try {
// 创建表
await client.query(`
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
// 插入数据
const insertResult = await client.query(
"INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id",
["Jane Doe", "jane@example.com"]
);
const userId = insertResult.rows[0].id;
// 查询数据
const { rows } = await client.query("SELECT * FROM users WHERE id = $1", [
userId,
]);
console.log("User:", rows[0]);
} catch (err) {
console.error("Error:", err);
} finally {
client.release();
}
}
NoSQL 数据库
MongoDB
1. 基本连接
javascript
const { MongoClient } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
async function connectMongo() {
try {
await client.connect();
return client.db("test");
} catch (err) {
console.error("MongoDB connection error:", err);
throw err;
}
}
2. 基本操作
javascript
async function mongoOperations() {
const db = await connectMongo();
const users = db.collection("users");
try {
// 插入文档
const insertResult = await users.insertOne({
name: "John Doe",
email: "john@example.com",
age: 30,
createdAt: new Date(),
});
console.log("Inserted ID:", insertResult.insertedId);
// 查询文档
const user = await users.findOne({ _id: insertResult.insertedId });
console.log("User:", user);
// 更新文档
await users.updateOne(
{ _id: insertResult.insertedId },
{ $set: { age: 31 } }
);
// 删除文档
await users.deleteOne({ _id: insertResult.insertedId });
// 聚合查询
const result = await users
.aggregate([
{ $match: { age: { $gt: 25 } } },
{ $group: { _id: null, avgAge: { $avg: "$age" } } },
])
.toArray();
} catch (err) {
console.error("Error:", err);
} finally {
await client.close();
}
}
Redis
1. 基本连接
javascript
const Redis = require("ioredis");
const redis = new Redis({
host: "localhost",
port: 6379,
password: "password",
});
2. 基本操作
javascript
async function redisOperations() {
try {
// 字符串操作
await redis.set("user:1:name", "John Doe");
const name = await redis.get("user:1:name");
// 哈希表操作
await redis.hset("user:1", {
name: "John Doe",
email: "john@example.com",
age: "30",
});
const user = await redis.hgetall("user:1");
// 列表操作
await redis.lpush("messages", "Hello");
await redis.rpush("messages", "World");
const messages = await redis.lrange("messages", 0, -1);
// 集合操作
await redis.sadd("users:online", "user:1", "user:2");
const onlineUsers = await redis.smembers("users:online");
// 有序集合操作
await redis.zadd("scores", 100, "user:1");
const topScores = await redis.zrevrange("scores", 0, -1, "WITHSCORES");
} catch (err) {
console.error("Redis Error:", err);
}
}
ORM 框架
Sequelize
1. 基本设置
javascript
const { Sequelize, DataTypes } = require("sequelize");
const sequelize = new Sequelize("database", "username", "password", {
host: "localhost",
dialect: "mysql",
});
// 定义模型
const User = sequelize.define("User", {
name: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
age: {
type: DataTypes.INTEGER,
},
});
2. 基本操作
javascript
async function sequelizeOperations() {
try {
// 同步模型到数据库
await sequelize.sync();
// 创建记录
const user = await User.create({
name: "John Doe",
email: "john@example.com",
age: 30,
});
// 查询记录
const foundUser = await User.findOne({
where: { email: "john@example.com" },
});
// 更新记录
await user.update({ age: 31 });
// 删除记录
await user.destroy();
// 关联查询
const Post = sequelize.define("Post", {
title: DataTypes.STRING,
content: DataTypes.TEXT,
});
User.hasMany(Post);
Post.belongsTo(User);
const userWithPosts = await User.findOne({
include: Post,
});
} catch (err) {
console.error("Sequelize Error:", err);
}
}
Prisma
1. Schema 定义
prisma
// schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String
posts Post[]
profile Profile?
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
}
model Profile {
id Int @id @default(autoincrement())
bio String?
user User @relation(fields: [userId], references: [id])
userId Int @unique
}
2. 基本操作
javascript
const { PrismaClient } = require("@prisma/client");
const prisma = new PrismaClient();
async function prismaOperations() {
try {
// 创建用户和关联数据
const user = await prisma.user.create({
data: {
email: "john@example.com",
name: "John Doe",
posts: {
create: {
title: "Hello World",
content: "This is my first post",
},
},
profile: {
create: {
bio: "I am a software developer",
},
},
},
include: {
posts: true,
profile: true,
},
});
// 查询带关联数据的用户
const users = await prisma.user.findMany({
include: {
posts: true,
profile: true,
},
});
// 事务
const [post, profile] = await prisma.$transaction([
prisma.post.create({
data: {
title: "New Post",
authorId: user.id,
},
}),
prisma.profile.update({
where: { userId: user.id },
data: { bio: "Updated bio" },
}),
]);
} catch (err) {
console.error("Prisma Error:", err);
} finally {
await prisma.$disconnect();
}
}
最佳实践
1. 连接池管理
javascript
// MySQL 连接池
const pool = mysql.createPool({
connectionLimit: 10,
host: "localhost",
user: "root",
password: "password",
database: "test",
});
// MongoDB 连接池
const client = new MongoClient(uri, {
poolSize: 10,
useNewUrlParser: true,
useUnifiedTopology: true,
});
2. 错误处理
javascript
// 通用数据库错误处理
class DatabaseError extends Error {
constructor(message, originalError) {
super(message);
this.name = "DatabaseError";
this.originalError = originalError;
}
}
async function executeQuery(query, params) {
try {
const result = await pool.query(query, params);
return result;
} catch (err) {
throw new DatabaseError("Database query failed", err);
}
}
3. 事务管理
javascript
async function transferMoney(fromId, toId, amount) {
const connection = await pool.getConnection();
try {
await connection.beginTransaction();
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();
} catch (err) {
await connection.rollback();
throw new DatabaseError("Transaction failed", err);
} finally {
connection.release();
}
}
4. 查询优化
javascript
// 使用索引
await pool.query(`
CREATE INDEX idx_users_email ON users(email);
`);
// 使用预处理语句
const stmt = await connection.prepare("SELECT * FROM users WHERE email = ?");
// 分页查询
async function getUsers(page = 1, limit = 10) {
const offset = (page - 1) * limit;
const [users, total] = await Promise.all([
pool.query("SELECT * FROM users LIMIT ? OFFSET ?", [limit, offset]),
pool.query("SELECT COUNT(*) as total FROM users"),
]);
return {
users: users[0],
total: total[0][0].total,
pages: Math.ceil(total[0][0].total / limit),
};
}
5. 缓存策略
javascript
const Redis = require("ioredis");
const redis = new Redis();
async function getCachedUser(id) {
// 尝试从缓存获取
const cachedUser = await redis.get(`user:${id}`);
if (cachedUser) {
return JSON.parse(cachedUser);
}
// 从数据库获取
const user = await User.findByPk(id);
if (user) {
// 存入缓存
await redis.set(
`user:${id}`,
JSON.stringify(user),
"EX",
3600 // 1小时过期
);
}
return user;
}
6. 数据验证
javascript
const Joi = require("joi");
const userSchema = Joi.object({
name: Joi.string().min(3).max(30).required(),
email: Joi.string().email().required(),
age: Joi.number().integer().min(0).max(150),
});
async function createUser(userData) {
// 验证数据
const { error, value } = userSchema.validate(userData);
if (error) {
throw new ValidationError(error.details[0].message);
}
// 创建用户
return await User.create(value);
}
7. 安全性
javascript
// 参数化查询防止 SQL 注入
const result = await pool.query("SELECT * FROM users WHERE email = ?", [
userInput,
]);
// 加密敏感数据
const bcrypt = require("bcrypt");
async function hashPassword(password) {
const salt = await bcrypt.genSalt(10);
return await bcrypt.hash(password, salt);
}
// 数据脱敏
function sanitizeUser(user) {
const { password, ...sanitizedUser } = user;
return sanitizedUser;
}