MySQL核心知识

MySQL 核心知识完全指南

前言

MySQL 是目前最流行的开源关系型数据库管理系统之一。本文将系统性地梳理MySQL的核心知识,从基础操作到高级概念,帮助读者构建完整的知识体系。


1. 数据库基础操作

1.1 库级操作

库是数据库的顶层容器,管理所有表。

sql 复制代码
-- 创建数据库
CREATE DATABASE mydb;

-- 查看所有数据库
SHOW DATABASES;

-- 选择数据库
USE mydb;

-- 删除数据库(慎用!)
DROP DATABASE mydb;

1.2 表级操作

表是数据的存储单元,由行和列组成。

常用数据类型
分类 类型 说明
数值 INT, BIGINT 整数
DECIMAL(M, D) 精确小数,适合金额
DOUBLE 浮点数,不精确
字符串 CHAR(N) 定长,效率高,但浪费空间
VARCHAR(N) 变长,节省空间,最常用
TEXT 长文本
日期时间 DATE 仅日期
DATETIME 日期和时间
TIMESTAMP 时间戳,受时区影响
表结构管理
sql 复制代码
-- 建表
CREATE TABLE employee (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    salary DECIMAL(10, 2),
    hire_date DATE
);

-- 查看表结构
DESC employee;

-- 查看建表语句
SHOW CREATE TABLE employee \G;

-- 修改表结构
ALTER TABLE employee ADD COLUMN email VARCHAR(100);  -- 添加列
ALTER TABLE employee MODIFY COLUMN salary DECIMAL(12, 2); -- 修改列类型
ALTER TABLE employee CHANGE COLUMN name username VARCHAR(100); -- 重命名列
ALTER TABLE employee DROP COLUMN email; -- 删除列

-- 重命名表
RENAME TABLE employee TO staff;

-- 清空表(删除所有数据,但保留结构)
TRUNCATE TABLE staff;

-- 删除表
DROP TABLE staff;

2. 数据操作语言 (DML)

2.1 插入数据 (INSERT)

sql 复制代码
-- 1. 插入完整行(值的顺序必须与表字段顺序一致)
INSERT INTO employee VALUES (1, '张三', 5000.00, '2023-01-01');

-- 2. 插入指定字段
INSERT INTO employee (name, salary) VALUES ('李四', 6000.00);

-- 3. 批量插入
INSERT INTO employee (name, salary) VALUES ('王五', 5500.00), ('赵六', 7000.00);

-- 4. 从其他表插入数据(备份或复制)
CREATE TABLE emp_bak AS SELECT * FROM employee; -- 备份表(结构和数据)
INSERT INTO emp_bak SELECT * FROM employee; -- 向已存在的备份表插入数据

2.2 更新数据 (UPDATE)

sql 复制代码
-- 基本更新
UPDATE employee SET salary = 8000.00 WHERE name = '张三';

-- 相关更新:将emp_bak的工资更新为原表emp中的工资
UPDATE emp_bak eb
SET eb.salary = (SELECT e.salary FROM employee e WHERE e.id = eb.id);

2.3 删除数据 (DELETE)

sql 复制代码
-- 删除满足条件的行
DELETE FROM employee WHERE name = '李四';

-- 删除所有行(但速度慢,可回滚)
DELETE FROM employee;

3. 核心查询 (SELECT)

查询是数据库最核心的操作,其执行逻辑可以抽象为以下流程:
原始数据
FROM/JOIN: 确定数据源并关联表
WHERE: 行过滤
GROUP BY: 分组
HAVING: 组过滤
SELECT: 选择列并计算
ORDER BY: 排序
LIMIT: 限制结果
最终结果

3.1 基本查询与过滤

sql 复制代码
-- 查询特定字段
SELECT name, salary FROM employee;

-- 条件过滤
SELECT * FROM employee WHERE salary > 5000 AND (name LIKE '张%' OR name LIKE '王%');

-- 范围查询
SELECT * FROM employee WHERE id IN (1, 3, 5);
SELECT * FROM employee WHERE salary BETWEEN 5000 AND 8000;

3.2 排序 (ORDER BY)

sql 复制代码
-- 默认升序(ASC),降序(DESC)
SELECT * FROM employee ORDER BY salary DESC, name ASC;

3.3 聚合函数与分组 (GROUP BY ... HAVING)

聚合函数用于对一组值进行计算,返回单个值。

函数 作用
COUNT() 计数
SUM() 求和
AVG() 平均值
MAX() 最大值
MIN() 最小值
sql 复制代码
-- 计算每个部门的平均工资
SELECT dept_id, AVG(salary) AS avg_salary
FROM employee
GROUP BY dept_id;

-- 过滤出平均工资大于6000的部门
SELECT dept_id, AVG(salary) AS avg_salary
FROM employee
GROUP BY dept_id
HAVING AVG(salary) > 6000;

4. 约束 (Constraints)

约束是数据库层面保证数据完整性和一致性的规则。

约束类型 说明 示例
PRIMARY KEY 主键,唯一标识一行,非空且唯一 id INT PRIMARY KEY
FOREIGN KEY 外键,维护表间关系,确保引用完整性。 dept_id INT REFERENCES dept(id)
UNIQUE 唯一约束,列值不能重复,但可有多个NULL email VARCHAR(100) UNIQUE
NOT NULL 非空约束,列值不能为空。 name VARCHAR(100) NOT NULL
DEFAULT 默认值。 status INT DEFAULT 1
CHECK 检查约束,确保列值满足特定条件。 age INT CHECK (age >= 18)

关于外键的思考 :虽然外键能保证数据一致性,但在高并发、分布式系统中,它会带来性能瓶颈和维护成本。因此,很多企业会选择在应用层来维护数据关系,而非在数据库层使用外键。


5. 表关系与设计

数据库设计的关键在于识别实体间的关系。

5.1 关系类型及设计模式

一对一
一对多
多对多
多对多
1 1 1 1 1 * * * 用户
+string 用户名
+int 用户ID(PK)
身份证
+string 号码
+int 身份证ID(PK)
+int 用户ID(FK)
部门
+string 部门名
+int 部门ID(PK)
员工
+string 姓名
+int 员工ID(PK)
+int 部门ID(FK)
学生
+string 姓名
+int 学生ID(PK)
课程
+string 课程名
+int 课程ID(PK)
选课记录
+int 学生ID(FK, PK)
+int 课程ID(FK, PK)

一对一 (1:1)
  • 设计:主键关联 或 在外键上增加唯一约束。
  • 示例:用户表与用户扩展信息表。
一对多 (1:N)
  • 设计:在"多"的一方(从表)添加一个外键,指向"一"的一方(主表)的主键。
  • 示例:一个部门有多个员工。
多对多 (M:N)
  • 设计:创建一张中间表(关联表),包含两个外键,分别指向两张主表的主键。这两个外键通常组成联合主键。
  • 示例:学生选课,一个学生可选多门课,一门课可被多个学生选。
自关联
  • 应用:用于存储树形或层级结构数据,如菜单、组织架构、行政区划。
  • 设计 :表中包含一个指向自身主键的外键(如 parent_id)。
sql 复制代码
CREATE TABLE category (
    id INT PRIMARY KEY,
    name VARCHAR(60),
    parent_id INT,
    FOREIGN KEY (parent_id) REFERENCES category(id)
);

6. 连接查询 (JOIN)

连接查询是将多张表的数据基于关联条件合并到一起。其本质是笛卡尔积加上过滤条件。
内连接
左连接
右连接
表A
笛卡尔积
表B
JOIN 条件
两表都匹配的记录
左表所有记录 + 右表匹配记录
右表所有记录 + 左表匹配记录

6.1 内连接 (INNER JOIN)

只返回两个表中匹配的行。

sql 复制代码
-- 显示内连接
SELECT e.name, d.name AS dept_name
FROM employee e
INNER JOIN dept d ON e.dept_id = d.id;

-- 隐式内连接(老式写法)
SELECT e.name, d.name
FROM employee e, dept d
WHERE e.dept_id = d.id;

6.2 外连接 (OUTER JOIN)

以一个表为基准,返回其所有行,另一个表不匹配的行用 NULL 填充。

sql 复制代码
-- 左连接:以左表(employee)为准
SELECT e.name, d.name
FROM employee e
LEFT JOIN dept d ON e.dept_id = d.id;

-- 右连接:以右表(dept)为准
SELECT e.name, d.name
FROM employee e
RIGHT JOIN dept d ON e.dept_id = d.id;

7. 索引 (Index)

索引是提升查询性能的"加速器",其核心原理类似于书的目录。

7.1 索引的数据结构 (B+ Tree)

MySQL InnoDB 引擎使用 B+ Tree 作为索引结构。
特点

  1. 所有数据都在叶子节点 2. 叶子节点间有双向指针,支持范围查询 3. 树的高度低,IO次数少 B+树结构
    根节点: 5, 15
    叶子节点: 1,3,5
    叶子节点: 7,9,15
    数据页/行指针
    数据页/行指针

7.2 索引类型

类型 说明 特点
主键索引 基于主键自动创建 唯一,非空,聚簇索引(数据按主键顺序存放)
唯一索引 UNIQUE 约束创建 唯一,允许 NULL
普通索引 手动创建 无唯一性要求,用于加速查询
复合索引 多个列的组合 遵循最左前缀原则

7.3 最左前缀原则

对于复合索引 (a, b, c),查询条件必须包含 a,索引才会生效。例如:

  • WHERE a = 1 ✅ 生效
  • WHERE a = 1 AND b = 2 ✅ 生效
  • WHERE b = 2 AND c = 3 ❌ 不生效
  • WHERE a = 1 AND c = 3 ✅ 仅 a 生效

7.4 索引的使用建议

  • 该建索引的列WHEREORDER BYGROUP BY 中频繁使用的列。
  • 不该建索引的列:数据量小、更新频繁、区分度低的列(如性别)。
  • 代价:增、删、改操作变慢,占用额外存储空间。

8. 事务 (Transaction)

事务是保证数据一致性的逻辑单元,确保一组操作要么全部成功,要么全部失败。

8.1 ACID 特性

特性 描述
原子性 事务中的操作不可分割,要么都做,要么都不做。
一致性 事务执行前后,数据库的完整性约束未被破坏。
隔离性 并发事务之间互不干扰。
持久性 事务提交后,数据修改是永久性的。

8.2 事务操作

sql 复制代码
START TRANSACTION; -- 或 BEGIN

-- 执行一系列SQL
UPDATE account SET money = money - 1000 WHERE id = 1;
UPDATE account SET money = money + 1000 WHERE id = 2;

-- 提交(使变更永久生效)
COMMIT;

-- 回滚(撤销事务中的所有变更)
ROLLBACK;

8.3 并发事务问题与隔离级别

隔离级别 脏读 不可重复读 幻读 并发性能
读未提交 可能 可能 可能 最高
读已提交 避免 可能 可能
可重复读 (MySQL默认) 避免 避免 可能
串行化 避免 避免 避免 最低

问题解释

  • 脏读:读到其他事务未提交的数据。
  • 不可重复读:同一事务内,两次读取同一数据的结果不同(因其他事务更新并提交)。
  • 幻读:同一事务内,两次查询的记录数不同(因其他事务插入并提交)。

9. JDBC 基础

JDBC (Java Database Connectivity) 是 Java 程序访问数据库的标准 API。

9.1 JDBC 与 MySQL 事务

在 Java 代码中,我们可以通过 Connection 对象来控制事务边界。

java 复制代码
Connection conn = null;
try {
    // 1. 加载驱动,获取连接
    Class.forName("com.mysql.cj.jdbc.Driver");
    conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");

    // 2. 开启事务(关闭自动提交)
    conn.setAutoCommit(false); // 对应 SQL: START TRANSACTION

    // 3. 执行操作
    PreparedStatement ps1 = conn.prepareStatement("UPDATE account SET money = money - ? WHERE id = ?");
    ps1.setInt(1, 1000);
    ps1.setInt(2, 1);
    ps1.executeUpdate();

    PreparedStatement ps2 = conn.prepareStatement("UPDATE account SET money = money + ? WHERE id = ?");
    ps2.setInt(1, 1000);
    ps2.setInt(2, 2);
    ps2.executeUpdate();

    // 4. 提交事务
    conn.commit(); // 对应 SQL: COMMIT
    System.out.println("转账成功!");

} catch (Exception e) {
    // 5. 发生异常,回滚事务
    if (conn != null) {
        try {
            conn.rollback(); // 对应 SQL: ROLLBACK
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }
    e.printStackTrace();
} finally {
    // 6. 关闭连接等资源
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
相关推荐
anzhxu1 小时前
QT数据库(三):QSqlQuery使用
数据库·qt·oracle
德彪稳坐倒骑驴1 小时前
Oracle 11g安装
数据库·oracle
韩立学长2 小时前
Springboot校园跑腿业务系统0b7amk02(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·后端
阿贵---2 小时前
使用XGBoost赢得Kaggle比赛
jvm·数据库·python
想七想八不如114082 小时前
数据库--样题复习
数据库·sql·oracle
551只玄猫2 小时前
【数据库原理 实验报告1】创建和管理数据库
数据库·sql·学习·mysql·课程设计·实验报告·数据库原理
q5431470872 小时前
MySQL SQL100道基础练习题
数据库·mysql
zhoupenghui1683 小时前
mysql 中如果条件where中有or,则要求or两边的字段都必须有索引,否则不能用到索引, 为什么?
数据库·mysql·索引
eggwyw4 小时前
完美解决phpstudy安装后mysql无法启动
数据库·mysql