1. 数据库基础概述
数据库是现代信息系统的核心组件,就像一个大仓库,专门用来存储、管理和检索各种数据。我第一次接触数据库是在2008年参与一个学生管理系统开发时,当时就被它强大的数据组织能力所震撼。经过十多年的实践,我发现无论是网站、APP还是企业软件,几乎都离不开数据库的支持。
数据库主要解决三个核心问题:一是数据持久化存储,确保信息不会因为程序关闭而丢失;二是高效查询,能在海量数据中快速找到所需内容;三是数据一致性,保证多个用户同时操作时不会产生冲突。常见的数据库类型有关系型数据库(如MySQL、PostgreSQL)和非关系型数据库(如MongoDB、Redis),它们各有适用场景。
提示:初学者常犯的错误是过早纠结于选择哪种数据库。实际上,在项目初期,先掌握基本概念和SQL语法更为重要。
2. 关系型数据库核心概念
2.1 表结构与数据类型
关系型数据库的核心是"表",就像Excel表格一样由行和列组成。每张表都有一个明确的表结构定义,包括字段名和数据类型。常见的数据类型有:
- 整数类型:INT, BIGINT
- 小数类型:DECIMAL(10,2)
- 字符串:VARCHAR(255)
- 日期时间:DATETIME
- 布尔值:BOOLEAN
我在电商项目中就曾因为数据类型选择不当吃过亏。比如用VARCHAR存储手机号码,导致无法进行数值范围查询;用DATETIME存储生日,结果包含了不必要的时间信息。正确的做法是:
CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL, phone CHAR(11) NOT NULL, birth_date DATE, balance DECIMAL(10,2) DEFAULT 0.00 );2.2 主键与外键
主键是表的唯一标识符,就像身份证号一样确保每行数据都是唯一的。我习惯使用自增整数作为主键,因为这样既简单又高效。外键则用于建立表与表之间的关系,比如订单表引用用户表的ID:
CREATE TABLE orders ( order_id INT PRIMARY KEY, user_id INT, order_date DATETIME, FOREIGN KEY (user_id) REFERENCES users(id) );注意:虽然外键能保证数据完整性,但在高并发系统中可能会影响性能。我在处理千万级数据时,通常会在应用层实现这种约束关系。
3. SQL语言基础
3.1 增删改查(CRUD)操作
SQL是与数据库交互的标准语言。最基本的CRUD操作包括:
- 插入数据:
INSERT INTO users (username, phone) VALUES ('张三', '13800138000');- 查询数据:
-- 简单查询 SELECT * FROM users WHERE birth_date > '1990-01-01'; -- 多表连接查询 SELECT u.username, o.order_id FROM users u JOIN orders o ON u.id = o.user_id;- 更新数据:
UPDATE users SET balance = balance + 100 WHERE username = '张三';- 删除数据:
DELETE FROM orders WHERE order_date < '2020-01-01';3.2 高级查询技巧
在实际项目中,我经常使用这些高级查询技术:
- 聚合函数:
SELECT COUNT(*) as user_count, AVG(balance) as avg_balance FROM users;- 分组查询:
SELECT YEAR(birth_date) as birth_year, COUNT(*) as count FROM users GROUP BY birth_year HAVING count > 10;- 子查询:
SELECT username FROM users WHERE id IN (SELECT DISTINCT user_id FROM orders);4. 数据库设计与优化
4.1 范式与反范式
数据库设计通常遵循范式化原则,以减少数据冗余。但完全范式化可能导致查询性能下降。我的经验法则是:
- 小型系统:遵循第三范式(3NF)
- 大型系统:适当反范式化,比如将常用查询结果预计算存储
例如在电商系统中,虽然订单总价可以通过累加商品价格计算,但我会直接在订单表中存储total_amount字段,避免每次查询都要计算。
4.2 索引优化
索引就像书的目录,能大幅提高查询速度。我常用的索引策略包括:
- 为WHERE条件中的字段创建索引
- 为JOIN操作的关联字段创建索引
- 为ORDER BY字段创建索引
-- 创建普通索引 CREATE INDEX idx_username ON users(username); -- 创建复合索引 CREATE INDEX idx_name_phone ON users(username, phone);重要提示:索引不是越多越好。每个索引都会占用空间并降低写入速度。我曾遇到一个表有20多个索引,导致插入性能极差。
5. 事务与并发控制
5.1 ACID特性
事务是数据库操作的逻辑单元,具有ACID特性:
- 原子性(Atomicity):要么全部成功,要么全部失败
- 一致性(Consistency):保持数据状态合法
- 隔离性(Isolation):并发事务互不干扰
- 持久性(Durability):一旦提交永久有效
BEGIN TRANSACTION; UPDATE accounts SET balance = balance - 100 WHERE id = 1; UPDATE accounts SET balance = balance + 100 WHERE id = 2; COMMIT;5.2 隔离级别
不同的隔离级别会影响并发性能和数据一致性:
- 读未提交(Read Uncommitted):性能最好,但可能读到脏数据
- 读已提交(Read Committed):Oracle/PostgreSQL默认级别
- 可重复读(Repeatable Read):MySQL默认级别
- 串行化(Serializable):最严格,性能最差
我在支付系统中通常使用Read Committed级别,在确保一致性的同时保持较好性能。
6. 数据库安全与备份
6.1 权限管理
良好的权限控制能有效防止数据泄露。我建议:
- 为每个应用创建专用数据库账号
- 遵循最小权限原则
- 定期审计权限分配
-- 创建只读用户 CREATE USER 'report_user'@'%' IDENTIFIED BY 'password'; GRANT SELECT ON mydb.* TO 'report_user'@'%';6.2 备份策略
没有备份的数据库就像没有降落伞的跳伞。我的备份方案包括:
- 每日全量备份 + binlog增量备份
- 备份文件异地存储
- 定期恢复测试
# MySQL全量备份示例 mysqldump -u root -p --all-databases > backup.sql7. 常见问题排查
7.1 慢查询优化
当遇到查询缓慢时,我的排查步骤是:
- 使用EXPLAIN分析执行计划
- 检查是否缺少合适索引
- 优化SQL语句结构
- 考虑重构查询方式
EXPLAIN SELECT * FROM users WHERE username LIKE '%张%';7.2 连接池配置
数据库连接是宝贵资源。我推荐的连接池配置原则:
- 初始连接数 = CPU核心数 × 2
- 最大连接数不超过数据库限制的80%
- 设置合理的超时时间
# HikariCP配置示例 spring.datasource.hikari.maximum-pool-size=20 spring.datasource.hikari.idle-timeout=30000在实际项目中,我发现很多性能问题都源于不合理的连接池配置。曾经有个系统因为连接泄漏导致数据库连接耗尽,整个系统瘫痪。后来我们引入了连接监控工具,定期检查连接使用情况,问题才得到解决。