MySQL、MongoDB、Redis详解 | 从零基础到精通 | 包含设计、优化和实战
数据库是一个有组织的、可被查询的数据集合。它是现代应用程序的核心,用来存储和管理应用的所有数据。
| 特性 | 关系型(SQL) | 非关系型(NoSQL) |
|---|---|---|
| 数据结构 | 表格(行和列) | 文档、键值、图等 |
| ACID特性 | 强一致性 | 最终一致性 |
| 扩展性 | 垂直扩展 | 水平扩展 |
| 查询语言 | SQL | 各种查询方式 |
| 适用场景 | 结构化数据 | 非结构化数据 |
MySQL是最流行的开源关系型数据库。它以可靠性、易用性和性能著称,被广泛用于Web应用。
# Windows - 下载安装程序
# https://dev.mysql.com/downloads/mysql/
# macOS - 使用Homebrew
brew install mysql
# Linux - Ubuntu/Debian
sudo apt-get install mysql-server
# 验证安装
mysql --version-- 创建数据库
CREATE DATABASE myapp;
USE myapp;
-- 创建用户表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 创建订单表
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
total_amount DECIMAL(10, 2),
status VARCHAR(20) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);-- 插入数据
INSERT INTO users (username, email, password)
VALUES ('alice', 'alice@example.com', 'hashed_password');
-- 查询数据
SELECT * FROM users;
SELECT username, email FROM users WHERE id = 1;
-- 更新数据
UPDATE users SET email = 'newemail@example.com' WHERE id = 1;
-- 删除数据
DELETE FROM users WHERE id = 1;-- 连接查询
SELECT u.username, o.total_amount
FROM users u
JOIN orders o ON u.id = o.user_id;
-- 聚合函数
SELECT COUNT(*) as total_users FROM users;
SELECT SUM(total_amount) FROM orders;
SELECT AVG(total_amount) FROM orders;
-- 分组
SELECT user_id, COUNT(*) as order_count
FROM orders
GROUP BY user_id
HAVING order_count > 5;
-- 排序和限制
SELECT * FROM users ORDER BY created_at DESC LIMIT 10;-- 创建索引
CREATE INDEX idx_username ON users(username);
CREATE INDEX idx_user_id ON orders(user_id);
-- 复合索引
CREATE INDEX idx_user_status ON orders(user_id, status);
-- 查看索引
SHOW INDEX FROM users;
-- 删除索引
DROP INDEX idx_username ON users;MongoDB是一个文档型NoSQL数据库。它以灵活的数据模型和高性能著称,适合处理非结构化数据。
# macOS
brew tap mongodb/brew
brew install mongodb-community
# Linux - Ubuntu
curl -fsSL https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -
sudo apt-get install -y mongodb-org
# 启动MongoDB
mongod// 连接数据库
use myapp
// 插入文档
db.users.insertOne({
username: "alice",
email: "alice@example.com",
age: 25,
roles: ["user", "admin"],
created_at: new Date()
})
// 查询文档
db.users.find()
db.users.find({ username: "alice" })
db.users.find({ age: { $gt: 20 } })
// 更新文档
db.users.updateOne(
{ username: "alice" },
{ $set: { email: "newemail@example.com" } }
)
// 删除文档
db.users.deleteOne({ username: "alice" })// 条件查询
db.users.find({ age: { $gte: 18, $lte: 65 } })
db.users.find({ roles: { $in: ["admin", "moderator"] } })
// 排序和分页
db.users.find().sort({ created_at: -1 }).limit(10).skip(0)
// 聚合管道
db.users.aggregate([
{ $match: { age: { $gte: 18 } } },
{ $group: { _id: null, avg_age: { $avg: "$age" } } },
{ $sort: { avg_age: -1 } }
])
// 创建索引
db.users.createIndex({ username: 1 })
db.users.createIndex({ email: 1 }, { unique: true })const { MongoClient } = require('mongodb');
const client = new MongoClient('mongodb://localhost:27017');
async function main() {
try {
await client.connect();
const db = client.db('myapp');
const users = db.collection('users');
// 插入
await users.insertOne({
username: 'bob',
email: 'bob@example.com'
});
// 查询
const user = await users.findOne({ username: 'bob' });
console.log(user);
} finally {
await client.close();
}
}
main();灵活的数据模型、易于扩展、天然支持JSON。适合快速开发和原型设计。
Redis是一个高性能的键值存储数据库。它以极快的速度著称,常用作缓存和会话存储。
# macOS
brew install redis
# Linux
sudo apt-get install redis-server
# 启动Redis
redis-server
# 连接Redis
redis-cli-- 字符串操作
SET key1 "value1"
GET key1
APPEND key1 " more"
STRLEN key1
INCR counter
DECR counter
-- 过期时间
EXPIRE key1 3600 # 1小时后过期
TTL key1 # 查看剩余时间
PERSIST key1 # 移除过期时间
-- 列表操作
LPUSH mylist "a" "b" "c"
RPUSH mylist "d"
LRANGE mylist 0 -1
LPOP mylist
RPOP mylist
-- 集合操作
SADD myset "a" "b" "c"
SMEMBERS myset
SCARD myset
SISMEMBER myset "a"
-- 有序集合
ZADD scores 100 "alice" 90 "bob"
ZRANGE scores 0 -1 WITHSCORES
ZRANK scores "alice"const redis = require('redis');
const client = redis.createClient();
client.on('error', (err) => console.log('Redis Client Error', err));
async function main() {
await client.connect();
// 设置值
await client.set('user:1:name', 'Alice');
// 获取值
const name = await client.get('user:1:name');
console.log(name); // Alice
// 设置过期时间
await client.setEx('session:123', 3600, 'user_data');
// 列表操作
await client.lPush('queue', 'task1', 'task2');
const task = await client.lPop('queue');
await client.disconnect();
}
main();// 缓存穿透:使用布隆过滤器或缓存空值
async function getUser(userId) {
// 先查缓存
const cached = await redis.get(`user:${userId}`);
if (cached) return JSON.parse(cached);
// 查数据库
const user = await db.users.findById(userId);
// 缓存结果(包括空值)
if (user) {
await redis.setEx(`user:${userId}`, 3600, JSON.stringify(user));
} else {
await redis.setEx(`user:${userId}:null`, 300, '');
}
return user;
}
// 缓存更新:删除旧缓存
async function updateUser(userId, data) {
await db.users.updateOne({ _id: userId }, data);
await redis.del(`user:${userId}`);
}-- 好的设计
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50) UNIQUE,
email VARCHAR(100),
created_at TIMESTAMP
);
CREATE TABLE posts (
id INT PRIMARY KEY,
user_id INT,
title VARCHAR(200),
content TEXT,
created_at TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
-- 避免冗余
-- 不要在posts表中重复存储username
-- 需要时通过JOIN获取在设计数据库前,先画ER图确定实体和关系:
好的数据库设计能减少冗余、提高查询效率。花时间在设计阶段是值得的。
-- 使用EXPLAIN分析查询
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
-- 优化前:全表扫描
SELECT * FROM orders WHERE status = 'pending' AND created_at > '2024-01-01';
-- 优化后:使用索引
CREATE INDEX idx_status_date ON orders(status, created_at);
-- 避免SELECT *
SELECT id, username, email FROM users; -- 更好
-- 使用LIMIT
SELECT * FROM users LIMIT 10; -- 比SELECT *更快const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'myapp',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
async function query(sql, values) {
const connection = await pool.getConnection();
try {
const [rows] = await connection.execute(sql, values);
return rows;
} finally {
connection.release();
}
}-- 批量插入(比逐条插入快)
INSERT INTO users (username, email) VALUES
('alice', 'alice@example.com'),
('bob', 'bob@example.com'),
('charlie', 'charlie@example.com');
-- 批量更新
UPDATE users SET status = 'active' WHERE created_at > '2024-01-01';# 完整备份
mysqldump -u root -p myapp > backup.sql
# 备份特定表
mysqldump -u root -p myapp users orders > backup.sql
# 恢复备份
mysql -u root -p myapp < backup.sql
# 增量备份(基于二进制日志)
# 启用二进制日志,定期备份# 备份整个数据库
mongodump --db myapp --out ./backup
# 恢复
mongorestore --db myapp ./backup/myapp
# 备份特定集合
mongodump --db myapp --collection users --out ./backup-- 创建用户
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'strong_password';
-- 授予权限
GRANT SELECT, INSERT, UPDATE ON myapp.* TO 'appuser'@'localhost';
-- 撤销权限
REVOKE INSERT ON myapp.* FROM 'appuser'@'localhost';
-- 删除用户
DROP USER 'appuser'@'localhost';// 危险的做法
const username = req.body.username;
const query = `SELECT * FROM users WHERE username = '${username}'`;
// 安全的做法(使用参数化查询)
const query = 'SELECT * FROM users WHERE username = ?';
const result = await db.query(query, [username]);
// 使用ORM
const user = await User.findOne({ username: username });const bcrypt = require('bcrypt');
// 密码加密
async function hashPassword(password) {
const salt = await bcrypt.genSalt(10);
return await bcrypt.hash(password, salt);
}
// 密码验证
async function verifyPassword(password, hash) {
return await bcrypt.compare(password, hash);
}
// 敏感数据加密
const crypto = require('crypto');
function encrypt(text, key) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return iv.toString('hex') + ':' + encrypted.toString('hex');
}永远不要在代码中硬编码数据库密码。使用环境变量或密钥管理服务。
-- 用户表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
phone VARCHAR(20),
address TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 商品表
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(200) NOT NULL,
category_id INT,
description TEXT,
price DECIMAL(10, 2),
stock INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES categories(id)
);
-- 订单表
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
total_amount DECIMAL(10, 2),
status VARCHAR(20) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
-- 订单项目表
CREATE TABLE order_items (
id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT,
price DECIMAL(10, 2),
FOREIGN KEY (order_id) REFERENCES orders(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
-- 评价表
CREATE TABLE reviews (
id INT PRIMARY KEY AUTO_INCREMENT,
product_id INT NOT NULL,
user_id INT NOT NULL,
rating INT CHECK (rating >= 1 AND rating <= 5),
comment TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (product_id) REFERENCES products(id),
FOREIGN KEY (user_id) REFERENCES users(id)
);
-- 创建索引
CREATE INDEX idx_user_id ON orders(user_id);
CREATE INDEX idx_product_id ON order_items(product_id);
CREATE INDEX idx_status ON orders(status);
CREATE INDEX idx_created_at ON orders(created_at);-- 获取用户的订单列表
SELECT o.id, o.total_amount, o.status, o.created_at
FROM orders o
WHERE o.user_id = 1
ORDER BY o.created_at DESC;
-- 获取订单详情
SELECT oi.product_id, p.name, oi.quantity, oi.price
FROM order_items oi
JOIN products p ON oi.product_id = p.id
WHERE oi.order_id = 1;
-- 获取商品的平均评分
SELECT AVG(rating) as avg_rating, COUNT(*) as review_count
FROM reviews
WHERE product_id = 1;
-- 获取销售最好的商品
SELECT p.id, p.name, SUM(oi.quantity) as total_sold
FROM products p
JOIN order_items oi ON p.id = oi.product_id
GROUP BY p.id
ORDER BY total_sold DESC
LIMIT 10;通过这个案例,你学会了如何设计一个完整的数据库系统,包括表设计、关系建立和复杂查询。
现在你已经掌握了数据库的核心知识。
数据库学习最重要的是实践。建议你创建一个真实的项目,实际操作这些概念。