📚 完整教程目录

前言:什么是数据库?

🤔 数据库的定义

数据库是一个有组织的、可被查询的数据集合。它是现代应用程序的核心,用来存储和管理应用的所有数据。

为什么需要数据库?

数据库的应用场景

💡 重点:数据库是任何应用程序的基础。学好数据库,你就掌握了应用开发的核心。

数据库类型详解

关系型数据库 vs 非关系型数据库

特性 关系型(SQL) 非关系型(NoSQL)
数据结构 表格(行和列) 文档、键值、图等
ACID特性 强一致性 最终一致性
扩展性 垂直扩展 水平扩展
查询语言 SQL 各种查询方式
适用场景 结构化数据 非结构化数据

主要数据库类型

MySQL完全指南

什么是MySQL?

MySQL是最流行的开源关系型数据库。它以可靠性、易用性和性能著称,被广泛用于Web应用。

安装MySQL

# 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) );

CRUD操作

-- 插入数据 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详解

什么是MongoDB?

MongoDB是一个文档型NoSQL数据库。它以灵活的数据模型和高性能著称,适合处理非结构化数据。

核心概念

安装MongoDB

# 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 })

与Node.js集成

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();
✨ MongoDB优势:

灵活的数据模型、易于扩展、天然支持JSON。适合快速开发和原型设计。

Redis缓存数据库

什么是Redis?

Redis是一个高性能的键值存储数据库。它以极快的速度著称,常用作缓存和会话存储。

Redis的特点

安装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"

与Node.js集成

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}`); }
⚠️ 注意:Redis数据存储在内存中,重启后会丢失。要配置持久化或使用集群。

数据库设计原则

范式化设计

设计最佳实践

-- 好的设计 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图设计

在设计数据库前,先画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';

缓存策略

备份和恢复

MySQL备份

# 完整备份 mysqldump -u root -p myapp > backup.sql # 备份特定表 mysqldump -u root -p myapp users orders > backup.sql # 恢复备份 mysql -u root -p myapp < backup.sql # 增量备份(基于二进制日志) # 启用二进制日志,定期备份

MongoDB备份

# 备份整个数据库 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';

防止SQL注入

// 危险的做法 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;
✨ 实战总结:

通过这个案例,你学会了如何设计一个完整的数据库系统,包括表设计、关系建立和复杂查询。

🎉 数据库学习完成

现在你已经掌握了数据库的核心知识。

✅ 你现在可以:

🚀 下一步学习

  1. 学习ORM框架(Sequelize、Mongoose)
  2. 学习数据库集群和分片
  3. 学习消息队列(RabbitMQ、Kafka)
  4. 学习搜索引擎(Elasticsearch)
💡 建议:

数据库学习最重要的是实践。建议你创建一个真实的项目,实际操作这些概念。