MySQL 全套学习笔记(JDBC+连接池)

MySQL 全套学习笔记(JDBC+连接池)

MySQL 全套学习笔记(JDBC+连接池)一、DDL 数据库、表结构操作1. 数据库操作2. 表基础操作3. 建表模板4. ALTER TABLE 修改表结构5. 约束汇总6. 常用数据类型二、DML 增删改操作1. INSERT 插入数据2. UPDATE 更新数据3. DELETE 和 TRUNCATE三、SELECT 查询(重点)1. 基础查询2. 多表连接 JOIN自连接(同一张表自己连自己)四、外键 FOREIGN KEY1. 建表时定义外键2. 已有表追加外键3. 删除外键级联选项(写在references后面)五、高频错误速查表六、标准操作流程七、MySQL 排序+分页1. ORDER BY 升序、降序2. LIMIT 分页分页公式SQL书写顺序(不能乱)高频坑点八、MySQL 事务1. 什么是事务2. 事务四大特性 ACID(必考)3. 事务操作基本命令4. 事务的自动提交5. 并发事务会产生的3个问题6. 4种隔离级别(由低到高)7. InnoDB 与 MyISAM事务演示SQL(转账案例)九、常用函数 + 聚合函数 + 分组过滤 + MD5加密一、单行函数(一行返回一个结果)1. 字符串函数2. 数值函数3. 日期函数4. 流程函数(判断)二、聚合函数(多行返回1个结果,只对非NULL值统计)三、分组查询 GROUP BY + 分组过滤 HAVINGWHERE 和 HAVING 核心区别(必考)四、MD5加密配套练习SQL十、索引一、索引是什么二、索引分类三、索引操作语句(测试用)四、索引设计原则五、索引失效常见情况(高频考点)六、索引测试思路十一、MySQL 用户管理1. 创建用户2. 修改用户密码3. 删除用户4. 用户授权 GRANT(重点)5. 查看用户权限6. 撤销权限 REVOKE7. 刷新权限(考点!)8. 高频考点汇总十二、数据库设计完整流程(通用,MySQL为主)一、需求分析(第一步)二、概念模型:E-R图三、逻辑模型:设计表结构(核心)三大范式(尽量遵守)表字段设计要点四、表关系示例(文字格斗游戏举例)五、物理设计(建库建表、索引)六、校验与优化七、落地步骤总结十三、数据库备份mysqldump 命令行导出导入sql十四、JDBC & 数据库连接池(Druid)1. 是什么2. 核心好处3. 核心参数(必背)4. 常见连接池实现5. 核心API(JDBC规范:javax.sql.DataSource)6. Druid快速入门示例7. 连接池工作流程8. 对比:原生JDBC vs 连接池9. 面试考点10. 常见坑


一、DDL 数据库、表结构操作

DDL:定义库、表、字段,关键字 create / alter / drop

1. 数据库操作

复制代码
CREATE DATABASE IF NOT EXISTS school;   -- 创建数据库
DROP DATABASE IF EXISTS school;         -- 删除数据库
USE school;                             -- 切换数据库(必做!)
SHOW DATABASES;                         -- 查看所有数据库

2. 表基础操作

复制代码
SHOW TABLES;                            -- 查看当前库全部表
DESC student;                           -- 查看表字段结构
SHOW CREATE TABLE student;              -- 查看完整建表语句
DROP TABLE IF EXISTS student;           -- 删除表

3. 建表模板

复制代码
CREATE TABLE IF NOT EXISTS `student` (
`id` INT(10) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`sex` VARCHAR(2) NOT NULL DEFAULT '男' COMMENT '性别',
`birthday` DATE DEFAULT NULL COMMENT '生日',
`address` VARCHAR(20) DEFAULT NULL COMMENT '地址',
`email` VARCHAR(20) DEFAULT NULL COMMENT '邮件',
PRIMARY KEY (`id`)
);

建表注意事项

  1. 表名、字段名使用英文反引号 `````;字符串、注释使用英文单引号 ```'`

  2. 最后一个字段后面不要写逗号

  3. AUTO_INCREMENT 只能给整数主键使用

  4. 全部符号必须英文半角,中文符号会报1064语法错误

4. ALTER TABLE 修改表结构

复制代码
ALTER TABLE student ADD `age` TINYINT COMMENT '年龄';                -- 新增字段
ALTER TABLE student ADD `age` TINYINT AFTER `name`;                 -- 指定位置新增
ALTER TABLE student DROP COLUMN `age`;                              -- 删除字段
ALTER TABLE student MODIFY `age` TINYINT NOT NULL DEFAULT 0;        -- 修改字段类型约束,不改名字
ALTER TABLE student CHANGE `age` `stu_age` TINYINT;                 -- 修改字段名+类型
ALTER TABLE student RENAME TO stu;                                   -- 修改表名
ALTER TABLE student ADD PRIMARY KEY(`id`);                           -- 添加主键
ALTER TABLE student DROP PRIMARY KEY;                                -- 删除主键

注意:DROP删除字段,该列全部数据丢失;已有数据时修改字段类型不能冲突。

5. 约束汇总

约束 作用
NOT NULL 非空,字段不能为空
DEFAULT '值' 默认值,不赋值自动填充
PRIMARY KEY 主键:唯一、非空,一张表只能有一个
AUTO_INCREMENT 自增,整数类型,配合主键使用
FOREIGN KEY 外键,维护两张表引用关系

6. 常用数据类型

  1. 数值
  • INT:普通整数,id编号

  • TINYINT:小整数,年龄、状态

  • DECIMAL(m,d):小数,存储金额,不要使用float

  1. 字符串
  • VARCHAR(n):可变长度字符串,最常用

  • CHAR(n):定长字符串,适合短固定内容

  1. 日期
  • DATE:yyyy‑MM‑dd 日期

  • DATETIME:yyyy‑MM‑dd HH:mm:ss 日期时间

    不建议用字符串存储日期


二、DML 增删改操作

DML:insert / update / delete,操作表里面的行数据

1. INSERT 插入数据

复制代码
-- 格式1 指定字段(推荐)
INSERT INTO student(name,sex) VALUES ('张三','男');
​
-- 格式2 全部字段,顺序和建表完全一致,不推荐
INSERT INTO student VALUES(1,'张三','男',NULL,NULL,NULL);
​
-- 格式3 批量插入
INSERT INTO student(name,sex)
VALUES
('张三','男'),
('李四','女');
​
-- 自增字段:不写该字段,数据库自动生成id
INSERT INTO student(name,sex) VALUES ('王五','男');
​
-- 查询结果插入表
INSERT INTO 表A(字段1,字段2) SELECT 字段1,字段2 FROM 表B;

插入要点

  1. 字符串、日期加英文单引号;数字不加引号;NULL不加引号

  2. NOT NULL字段必须给值,否则报错1364

  3. 有外键约束:子表外键值必须在主表主键存在,报1452代表值不存在

2. UPDATE 更新数据

复制代码
--带where,正常使用
UPDATE student SET name='张三',sex='男' WHERE id=1;
​
--数值基于原值修改
UPDATE student SET score=score+5 WHERE id=1;
​
--多条件
UPDATE student SET gradeid=3 WHERE id>10 AND sex='男';

⚠高危!不加WHERE会修改全表所有行。更新前建议先用select校验where条件查询结果。

3. DELETE 和 TRUNCATE

复制代码
DELETE FROM student WHERE id=5;    -- 删除符合条件行,表结构保留
DELETE FROM student;                -- 删除全部数据,自增不重置,可以回滚
​
TRUNCATE TABLE student;             -- 清空整张表全部数据,表结构保留,id重置,不能回滚
​
DROP TABLE student;                 -- 删除整张表,结构+数据全部消失
对比项 DELETE TRUNCATE
类型 DML DDL
WHERE ✅支持 ❌不支持
自增主键 不重置 重置从1开始
事务回滚 可以回滚 不可回滚
速度 大数据量慢 速度很快

三、SELECT 查询(重点)

1. 基础查询

复制代码
SELECT * FROM student;                              -- 查询全部列
SELECT id,name FROM student;                         -- 查询指定列
SELECT name AS stuName FROM student;                 -- 字段别名
SELECT DISTINCT gradeid FROM student;                -- 去重
SELECT * FROM student ORDER BY id DESC;              -- 排序 DESC降序 ASC升序
SELECT * FROM student WHERE sex='男' AND id>2;       -- where条件

2. 多表连接 JOIN

on写两张表关联条件;where是拼接完成后过滤数据

复制代码
-- INNER JOIN 内连接:两边都匹配上,数据才展示
SELECT *
FROM student stu
INNER JOIN result r
ON stu.studentno = r.studentno;

-- LEFT JOIN 左连接:左表全部保留,右表匹配不到填NULL
SELECT *
FROM student stu
LEFT JOIN result r
ON stu.studentno = r.studentno;

-- RIGHT JOIN右连接:右表全部保留,开发很少使用

大坑:left join,不要把右表筛选条件写在where,会丢失左表数据,筛选右表条件写on后面。

自连接(同一张表自己连自己)

场景:一张表存在父子、上下级、层级关系;必须给表起两个不同别名

复制代码
SELECT
    e1.empname AS '员工姓名',
    e2.empname AS '直接上级'
FROM emp AS e1
LEFT JOIN emp AS e2
ON e1.leaderid = e2.empid;

e1看做员工,e2看做上级,物理上是同一张表 LEFT JOIN保留没有上级的顶层数据;INNER JOIN只查询有上级的员工


四、外键 FOREIGN KEY

主表:被引用;子表:引用别人;子表外键字段引用主表主键 引擎必须InnoDB;先建主表,再建子表;字段类型完全一致

1. 建表时定义外键

复制代码
CONSTRAINT `fk_student_gradeid` 
FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)
ON DELETE CASCADE
ON UPDATE CASCADE

2. 已有表追加外键

复制代码
ALTER TABLE student 
ADD CONSTRAINT fk_stu_gradeid FOREIGN KEY(gradeid) REFERENCES grade(gradeid);

3. 删除外键

复制代码
SHOW CREATE TABLE student; --查看外键名字
ALTER TABLE student DROP FOREIGN KEY fk_stu_gradeid;

级联选项(写在references后面)

参数 作用
CASCADE 主表更新删除,子表跟着更新删除
SET NULL 主表删除,子表外键置NULL,字段必须允许null
NO ACTION/RESTRICT(默认) 子表有引用,主表不能修改删除,直接报错

默认规则:插入先主表,再子表;删除先子表,再主表。 开发提示:很多项目不使用物理外键,业务代码做逻辑约束。


五、高频错误速查表

错误码 含义
1064 语法错误,中文符号、逗号、引号括号不匹配
1146 表不存在,忘记use切换数据库,表名拼写错误
1062 主键重复,插入已经存在的主键值
1364 NOT NULL字段没有默认值,插入没有给该字段赋值
1452 外键约束失败,子表外键的值主表不存在
1052 字段模糊歧义,多表查询重名字段没有加表别名

六、标准操作流程

  1. USE 库名;切换数据库

  2. 建表前 DROP TABLE IF EXISTS 表名;清理旧表

  3. 执行建表,确认全部符号英文半角

  4. DESC 表名;校验表结构

  5. 修改表用ALTER;update delete执行前先用select校验where条件

  6. 有外键:先操作主表,后操作子表。


七、MySQL 排序+分页

1. ORDER BY 升序、降序

复制代码
-- 升序 ASC:从小到大,默认,可以省略ASC
SELECT * FROM student ORDER BY id ASC;

-- 降序 DESC:从大到小,**不能省略**
SELECT * FROM student ORDER BY id DESC;

-- 多字段排序:先按第一个字段排,第一个值相同,再按第二个排
-- 先按age降序,年龄相同再按id升序
SELECT * FROM student ORDER BY age DESC, id ASC;

重点:ORDER BY写在WHERE条件后面

复制代码
SELECT * FROM student WHERE sex='男' ORDER BY id DESC;

2. LIMIT 分页

语法:LIMIT 起始下标,每页条数 ⚠️ 下标从0开始!不是从1

复制代码
-- 取前5条数据(第1页,0开始)
SELECT * FROM student LIMIT 0,5;

-- 第2页,每页5条:起始 = (页码-1)*每页条数
SELECT * FROM student LIMIT 5,5;

--简写:只写一个数字,代表从0开始取N条
SELECT * FROM student LIMIT 5;

分页公式

起始索引 = (当前页码 − 1) * 每页显示条数 例:页码3,每页10条 → (3‑1)*10 =20 → LIMIT 20,10

SQL书写顺序(不能乱)

复制代码
SELECT → FROM → WHERE → ORDER BY → LIMIT
SELECT *
FROM student
WHERE age>18
ORDER BY id DESC
LIMIT 0,3;

高频坑点

  1. LIMIT一定放整条SQL最后面,写在ORDER BY前面直接报错

  2. LIMIT第一个参数是下标,从0开始,不是页码

  3. DESC只作用于它紧贴的那一个字段,多字段排序每个字段要单独写DESC

  4. 大数据分页不建议直接用LIMIT 100000,10,性能差

记忆口诀:排序order by,desc降,asc升; where过滤完,再去排顺序; limit放末尾,下标从零起; 页码算偏移,(页‑1)*条数。


八、MySQL 事务

1. 什么是事务

事务(Transaction):一组不可分割的SQL操作,要么全部执行成功,要么全部失败回滚。 典型场景:转账,A扣钱、B加钱,不能只执行一半。

2. 事务四大特性 ACID(必考)

  • A 原子性 Atomicity:最小单元,要么全成,要么全失败。

  • C 一致性 Consistency:事务执行前后,数据完整性不变(总额不变)。

  • I 隔离性 Isolation:多个事务并发,事务之间互相隔离,互不干扰。

  • D 持久性 Durability:事务提交后,修改永久保存,断电也不会丢失。

3. 事务操作基本命令

复制代码
START TRANSACTION; -- 开启事务
-- 写DML语句(INSERT / UPDATE / DELETE)
COMMIT; -- 提交事务 → 数据永久生效
ROLLBACK; -- 回滚事务 → 撤销所有修改,恢复到开启前

注意:DDL语句(create/alter/drop)会自动提交事务,无法回滚。

4. 事务的自动提交

MySQL默认自动提交(autocommit=1),每执行一条DML就自动commit。

复制代码
SELECT @@autocommit; -- 查看自动提交状态
SET autocommit = 0; -- 关闭自动提交(当前会话)

5. 并发事务会产生的3个问题

  • 脏读:事务A读到了事务B未提交的数据(B最后回滚,A读到无效脏数据)

  • 不可重复读:同一个事务内,两次读取同一数据,中间被别的事务修改并提交,两次结果不一样(侧重数据修改)

  • 幻读:同一个事务内,两次查询,别的事务新增/删除数据,导致前后行数不一样(侧重新增删除)

6. 4种隔离级别(由低到高)

隔离级别 脏读 不可重复读 幻读
READ UNCOMMITTED 读未提交 ✅存在 ✅存在 ✅存在
READ COMMITTED 读已提交(Oracle默认) ❌避免 ✅存在 ✅存在
REPEATABLE READ 可重复读(MySQL InnoDB默认) ❌避免 ❌避免 ✅基本解决
SERIALIZABLE 串行化 ❌避免 ❌避免 ❌避免
复制代码
SELECT @@transaction_isolation; --查看隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL 级别名; --设置会话隔离级别

7. InnoDB 与 MyISAM

  • InnoDB:支持事务、行锁

  • MyISAM:不支持事务,表锁

一句话速记:事务ACID,开启提交回滚;并发会脏读、不可重复读、幻读;4个隔离级别,MySQL默认可重复读。

事务演示SQL(转账案例)

复制代码
-- 创建数据库
CREATE DATABASE shop CHARACTER SET utf8 COLLATE  utf8_general_ci;
USE shop;
-- 创建表
CREATE TABLE `shopping`(
`id` INT(3) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(30) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE = INNODB  DEFAULT CHARSET=utf8;
INSERT INTO `shopping`(`id`,`name`,`money`)
 VALUES 
(1,'zhangsan',1000),
(2,'lisi',500),
(3,'laowu',700);

SET autocommit = 0;-- 关闭自动事务
START TRANSACTION; -- 开启一个事务(一组事务)
UPDATE shopping SET money=money-500 WHERE NAME = 'zhangsan'; -- 张三-500
UPDATE shopping SET money=money+500 WHERE NAME = 'lisi'; -- 李四+500
COMMIT; -- 提交事务就被持久化了
ROLLBACK; -- 回滚

SET autocommit = 1; -- 恢复初始化 开启自动事务

九、常用函数 + 聚合函数 + 分组过滤 + MD5加密

一、单行函数(一行返回一个结果)

1. 字符串函数

  • CONCAT(str1,str2,...) 拼接字符串 CONCAT('zhang','san') → zhangsan

  • LENGTH(str) 获取字节长度(utf8中文1字3字节)

  • SUBSTRING(str,start,len) 截取字符串 SUBSTRING('abcde',2,3) → bcd

  • TRIM(str) 去掉前后空格

  • UPPER(str) 转大写;LOWER(str) 转小写

2. 数值函数

  • ROUND(x,n) 四舍五入,n保留小数位数 ROUND(3.1415,2) →3.14

  • FLOOR(x) 向下取整(往小取)FLOOR(3.9) →3

  • CEIL(x) 向上取整 CEIL(3.1) →4

  • RAND() 生成0~1随机小数

3. 日期函数

  • NOW() 获取当前日期+时间

  • CURDATE() 只获取当前日期

  • DATE_ADD(日期,INTERVAL 数字 单位) 日期加减 DATE_ADD(NOW(),INTERVAL 7 DAY) 当前时间加7天

  • DATEDIFF(end,start) 计算两个日期相差天数

4. 流程函数(判断)

  • IF(条件,值1,值2) 条件成立返回值1,否则值2

  • IFNULL(字段,默认值) 如果字段为null,返回默认值,否则返回字段本身

    重点:NULL参与运算结果一定是NULL,要用IFNULL处理

二、聚合函数(多行返回1个结果,只对非NULL值统计)

  • COUNT() 统计行数

    • COUNT(*):统计所有行(包含null行,推荐)

    • COUNT(列名):统计该列不为null的行数

  • SUM(列) 求和

  • AVG(列) 平均值

  • MAX(列) 最大值

  • MIN(列) 最小值

    ⚠注意:聚合函数不能直接写在WHERE后面!

三、分组查询 GROUP BY + 分组过滤 HAVING

语法模板

复制代码
SELECT 分组列, 聚合函数()
FROM 表名
[WHERE 普通行过滤条件]
GROUP BY 分组字段
[HAVING 聚合结果过滤]
ORDER BY 排序;

WHERE 和 HAVING 核心区别(必考)

  • WHERE:分组之前 过滤原始数据;不能使用聚合函数

  • HAVING:分组之后 ,对聚合后的结果过滤;可以写聚合函数 执行顺序:FROM → WHERE → GROUP BY → 聚合计算 → HAVING → SELECT → ORDER BY

示例:查询总金额大于1000的名字

复制代码
SELECT name,SUM(money) FROM shopping GROUP BY name HAVING SUM(money)>1000;

规则:select后面,非聚合的字段,必须出现在group by中

四、MD5加密

MD5是不可逆哈希摘要,不能解密还原原文,常用于密码存储。 特点:相同明文加密结果永远一样;不可逆,只能对比密文。

复制代码
-- 加密
SELECT MD5('123456');
-- 插入加密密码
INSERT INTO user(username,pwd) VALUES ('zhangsan',MD5('123456'));
-- 登录校验:输入密码加密后和数据库密文比对
SELECT * FROM user WHERE username='zhangsan' AND pwd = MD5('123456');

⚠重要考点 MD5不是加密算法,是哈希摘要,不可逆,无法解密 密文固定32位字符串 缺陷:简单密码可以被彩虹表破解;企业一般加盐 MD5(CONCAT('salt','123456'))
一句话速记:单行函数一行一结果;聚合多行算一个;WHERE分组前筛原始行,HAVING分组后筛聚合结果;MD5哈希不可逆,用来存密码。

配套练习SQL

复制代码
CREATE DATABASE IF NOT EXISTS testfunc;
USE testfunc;
CREATE TABLE `shopping` (
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR(20),
  money DECIMAL(10,2),
  create_time DATETIME
);
INSERT INTO shopping(NAME,money,create_time) VALUES
('zhangsan',1000,'2025-01-10 08:20:10'),
('lisi',500,'2025-01-11 09:10:20'),
('zhangsan',2000,'2025-01-12 10:30:00'),
('lisi',1500,'2025-01-13 14:20:10'),
('laowu',700,'2025-01-14 16:10:20');

-- 用户表,用于MD5练习
CREATE TABLE USER(
  id INT PRIMARY KEY AUTO_INCREMENT,
  username VARCHAR(20),
  PASSWORD CHAR(32)
);

-- 1.查询 name,把名字转为大写显示,列名别名大写名字
SELECT UPPER (`name`)AS '大写名字' FROM shopping;
-- 2. 查询 name,截取 name 前 2 个字符,别名 short_name
SELECT SUBSTRING(`name`,1,2) AS short_name FROM shopping;

-- 3. 计算 money 向上取整、向下取整、四舍五入保留 1 位小数
SELECT FLOOR(`money`) AS '向下取整' FROM shopping;
SELECT CEIL(`money`) AS '向上取整' FROM shopping;
SELECT ROUND (`money`) AS '四舍五入' FROM shopping;

-- 4. 查询当前时间,以及当前时间往后加 10 天的时间
SELECT NOW();
SELECT DATE_ADD(NOW(),INTERVAL 10 DAY);

-- 5. 判断 money,如果大于 1000 输出 '大额',否则 '小额'
SELECT IF(money>1000,'大额','小额')FROM shopping;
-- 6. IFNULL 练习:查询 money,如果 money 为 NULL 显示 0
SELECT IFNULL(money,0)FROM shopping;

-- 7. 统计一共有多少条记录
SELECT COUNT(*) FROM shopping;
-- 8. 查询 money 总和、平均值、最大值、最小值
SELECT SUM(money)FROM shopping;
SELECT MAX(money)FROM shopping;
SELECT MIN(money)FROM shopping;
SELECT AVG(money)FROM shopping;

-- 9. 按 name 分组,统计每个人总金额、平均金额
SELECT `name`,SUM(money) AS 总金额, AVG(money)AS 平均金额 FROM shopping
GROUP BY `name`;

-- 10. 按 name 分组,查询个人总金额大于 2000 的用户名和总金额
SELECT `name`,SUM(money) AS 总金额 FROM shopping
GROUP BY `name`
HAVING 总金额>2000;

-- 11. 查询 money>800 的数据,按 name 分组,筛选分组后总和 > 1500 的记录
SELECT `name` ,SUM(money) AS 金额 FROM shopping
WHERE  money>800
GROUP BY `name`
HAVING SUM(money)>1500;

-- 12. 插入用户,用户名:zhangsan,密码:123456,密码用 MD5 加密存入
INSERT INTO USER(`username`,`password`)VALUE('zhangsan',MD5('123456'));
-- 13. 校验登录:查询 user 表,匹配用户名 zhangsan,密码传入明文 123456 做 MD5 比对
SELECT PASSWORD FROM USER
WHERE username='zhangsan' AND PASSWORD=MD5('123456');

十、索引

一、索引是什么

索引相当于书的目录,帮数据库快速定位数据,加快查询速度;代价是占用磁盘空间,增删改(insert/update/delete)会变慢。 底层默认 InnoDB 使用 B+树

二、索引分类

  1. 主键索引(PRIMARY KEY) 主键自带索引,唯一+非空,一张表只能1个。 InnoDB主键索引又叫聚簇索引,数据存在主键索引叶子节点。

  2. 唯一索引(UNIQUE) 列值不能重复,允许NULL。

复制代码
CREATE UNIQUE INDEX idx_name ON 表名(字段);
  1. 普通索引(INDEX) 最基础索引,仅加速查询,值可重复、可为null。
复制代码
CREATE INDEX idx_money ON 表名(money);
  1. 联合索引(复合索引) 多个字段一起建索引,最左前缀原则(重点考点) index(a,b,c),查询条件必须从最左边a开始匹配,否则不走索引。

  2. 全文索引 FULLTEXT 用于长文本模糊搜索(文章、描述),不替代like %关键词%

聚簇索引 vs 非聚簇索引 聚簇:主键索引,索引和数据放一起,InnoDB才有 非聚簇:普通/唯一索引,叶子节点存主键值,查到主键再回表查数据

三、索引操作语句(测试用)

复制代码
-- 创建普通索引
CREATE INDEX idx_name ON student(name);

-- 查看表所有索引
SHOW INDEX FROM student;

-- 删除索引
DROP INDEX idx_name ON student;

-- 查看执行计划,测试是否走索引(核心!)
EXPLAIN SELECT * FROM student WHERE name='张三';

EXPLAIN看 type 字段判断索引使用: ALL → 全表扫描(没用到索引,最差) ref/range → 使用索引

四、索引设计原则

✅ 适合建索引

  • 经常出现在WHERE条件、JOIN连接、ORDER BY、GROUP BY 的字段

  • 字段区分度高(性别这种只有0/1不适合)

  • 数据量大的表,小表没必要建索引

❌ 不要建索引

  • 频繁更新修改的字段(update多,维护索引开销大)

  • 低基数字段:性别、状态(只有少数几种值)

  • 字段经常为NULL,或者大量重复值

  • 模糊查询 like '%关键词' ,前缀百分号不走索引;like '关键词%'可以走

五、索引失效常见情况(高频考点)

  1. 违背最左前缀原则(联合索引跳过左边字段)

  2. like 以 % 开头

  3. 索引列做运算、函数

  4. 字符串类型不加引号,发生隐式转换

  5. or 连接,一侧无索引

  6. MySQL优化器判断全表扫描比索引更快,自动放弃索引

六、索引测试思路

  1. 先用EXPLAIN查看执行计划

  2. 对比:不加索引的查询耗时 VS 加索引后的耗时

  3. 看type、key字段:key不为NULL代表用到索引

  4. 测试增删改:插入大量数据,观察加索引后速度变慢


十一、MySQL 用户管理

1. 创建用户

语法:CREATE USER '用户名'@'访问地址' IDENTIFIED BY '密码';

复制代码
CREATE USER 'user1'@'localhost' IDENTIFIED BY '123456';

'用户名'@'localhost':只能本机登录 'user1'@'%':任意IP都能远程登录 不加IDENTIFIED BY,创建无密码用户

2. 修改用户密码

复制代码
--方式1
ALTER USER 'root'@'localhost' IDENTIFIED BY '111111';
--方式2
SET PASSWORD FOR 'root'@'localhost' = '111111';

MySQL8.0 废弃 PASSWORD() 加密函数,不能再写PASSWORD('111111')

3. 删除用户

复制代码
DROP USER 'user1'@'localhost';

4. 用户授权 GRANT(重点)

复制代码
GRANT 权限列表 ON 库名.表名 TO '用户'@'地址' [WITH GRANT OPTION];
  • ALL PRIVILEGES:所有权限

  • ON *.* 所有库所有表;shop.* shop库全部表;shop.tb_user单张表

  • WITH GRANT OPTION:该用户可以把得到的权限授予其他人

复制代码
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION;

5. 查看用户权限

复制代码
SHOW GRANTS FOR 'root'@'localhost';

6. 撤销权限 REVOKE

复制代码
REVOKE 权限 ON 库.表 FROM '用户'@'地址';
--例子:收回全部权限
REVOKE ALL PRIVILEGES ON *.* FROM 'user1'@'localhost';

7. 刷新权限(考点!)

授权/撤销权限之后,执行刷新才生效

复制代码
FLUSH PRIVILEGES;

8. 高频考点汇总

账号格式:'用户名'@'主机',两部分是整体,主机写错用户就不生效(locallost 拼写错误经典坑)

  • %代表所有ip远程访问;localhost仅本机,192.168.1.%代表这个网段

  • WITH GRANT OPTION:仅代表传递授权,不代表拥有全部权限 区分: CREATE USER:只创建账号,没有任何权限 GRANT:专门分配权限

查看所有用户:

复制代码
SELECT user,host FROM mysql.user;

一句话背诵:建用户CREATE USER,改密码ALTER USER; 授权GRANT,撤权REVOKE; 改完权限FLUSH PRIVILEGES刷新; 账号是用户@主机,%代表任意远程IP。

复制代码
-- 创建用户 create user 用户名  IDENTIFIED BY '密码'
CREATE USER kuangshen IDENTIFIED BY '123456';
-- 修改密码
SET PASSWORD FOR 'root'@'localhost'='111111';
-- 重命名
RENAME USER kuangshen TO kuangshen2;
-- 用户授权 ALL PRIVILEGES 全部权限 库.表
-- ALL PRIVILEGES 除了给别人授权 什么都能干
GRANT ALL PRIVILEGES  ON *.* TO kuangshen2;
-- root用户权限
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION;
-- 查看权限  查看指定用户的权限
SHOW GRANTS FOR kuangshen2;
-- 撤销权限  REVOKE 哪些权限 在那个库,给谁撤销
REVOKE ALL PRIVILEGES ON *.* FROM kuangshen2;
-- 删除用户
DROP USER kuangshen2;

十二、数据库设计完整流程(通用,MySQL为主)

一、需求分析(第一步)

搞清楚项目有哪些实体(业务里的事物) 例:文字格斗游戏 → 用户、角色、道具、背包、战斗记录

  1. 找出实体的属性 用户:id、账号、密码、昵称、创建时间

  2. 找出实体之间关系

  • 一对一:用户 ↔ 用户详情

  • 一对多:用户 ↔ 多个背包记录(一个用户多个道具)

  • 多对多:角色 ↔ 技能(一个角色多个技能,技能可被多个角色拥有),多对多必须建中间表

二、概念模型:E-R图

实体(矩形)、属性(椭圆)、关系(菱形) 作用:只描述业务,不关心数据库语法

三、逻辑模型:设计表结构(核心)

三大范式(尽量遵守)

  1. 第一范式1NF:字段不可再拆分(不要把多个值放一个单元格,比如道具1,道具2存在同一字段)

  2. 第二范式2NF:非主键字段完全依赖主键,消除部分依赖(复合主键才会遇到)

  3. 第三范式3NF:非主键字段不能依赖其他非主键,消除传递依赖

注意:性能场景可以反范式(冗余字段,减少联表查询) 规范性和性能取舍: 关联查询的表不要超过三张表;商业化项目优先考虑性能,可适当增加冗余字段。

表字段设计要点

主键:id 一般用 BIGINT 自增,每张表都要有主键 外键:用来维护表关系,小项目可不用外键约束,代码层面控制关联

字段类型选择(MySQL)

  • 主键id:BIGINT AUTO_INCREMENT

  • 短字符串(账号、名称):VARCHAR(50)

  • 长文本(描述):TEXT

  • 数字(等级、数量):INT

  • 金额:DECIMAL(10,2),不要用float

  • 时间:DATETIME / TIMESTAMP,推荐DATETIME

  • 布尔:TINYINT(1) 0/1

字段约束 NOT NULL:必填字段 DEFAULT:默认值 UNIQUE:唯一(账号、手机号)

四、表关系示例(文字格斗游戏举例)

  • user 用户表 id, username, password, nickname, create_time

  • item 道具表 id, item_name, attack, desc

  • user_bag 用户背包(一对多) id, user_id, item_id, count

    user_id关联user.id,item_id关联item.id

五、物理设计(建库建表、索引)

建库:

复制代码
CREATE DATABASE game_db DEFAULT CHARACTER SET utf8mb4;

utf8mb4 支持emoji,优先用这个字符集

索引设计

  • 主键自带主键索引

  • 外键关联字段(user_id、item_id)加普通索引,加快联表查询

  • 查询频繁的字段加索引;不要滥用索引,索引会降低写入速度 引擎:默认 InnoDB(支持事务、外键)

六、校验与优化

检查:有没有重复数据、字段类型是否合理、关系是否正确 命名规范(推荐) 表名、字段名:小写+下划线,不要中文,不要驼峰 主键统一id;关联字段 user_id 预留扩展:预留状态字段status,时间字段方便后期排查

七、落地步骤总结

  1. 梳理业务,列出所有实体和属性

  2. 画E-R图,确定实体关系

  3. 拆分数据表,定义字段+类型+约束

  4. 设计索引,编写建表SQL

  5. 导入测试数据,验证查询逻辑

  6. 上线前做SQL性能测试


十三、数据库备份

为什么要备份: 保证重要的数据不丢失;数据转移

MYSQL数据备份的方式

  1. 直接拷贝物理文件

  2. 在sqlyog这种可视化工具中直接导出

用户备份

为什么要备份:

  • 保证重要的数据不丢失

  • 数据转移

MYSQL数据备份的方式

  • 直接拷贝物理文件

  • 在sqlyog这种可视化工具中直接导出

    • 在想要导出的表或者数据库上直接右击 选择备份或导出

mysqldump 命令行导出

复制代码
# mysqldump -h主机 -u用户名 -p密码 数据库 表名 >物理磁盘:/文件名
mysqldump  -hlocalhost -uroot -p123456 school student > Z:/a.sql

# 导出多张表
mysqldump  -hlocalhost -uroot -p123456 school student result > Z:/a.sql

# 导出整个库
mysqldump  -hlocalhost -uroot -p123456 school > Z:/a.sql

导入sql

复制代码
# 登录的情况下,切换到指定的数据库
source d:/a.sql;
# 未登录的情况
mysql -u用户名 -p密码 库名<备份文件

用途:备份数据库,防止数据丢失;把数据库给别人,直接发送SQL文件。


十四、JDBC & 数据库连接池(Druid)

1. 是什么

数据库连接是重量级资源,创建、关闭连接开销很大。 连接池:预先创建一批Connection放到池子里复用,用的时候从池拿,用完归还池子,不销毁

  • 不使用连接池:每次操作 → new Connection → 用完close销毁(慢、耗资源)

  • 使用连接池:启动预先建好连接 → 拿连接使用 → 归还(不销毁)

2. 核心好处

  1. 提升性能:避免频繁创建销毁连接,减少数据库压力

  2. 资源复用:连接重复使用

  3. 控制连接数量:限制最大连接数,防止数据库被大量连接打崩

  4. 统一管理:超时回收、空闲连接检测

3. 核心参数(必背)

  • initialSize 初始连接数:池子启动时预先创建多少连接

  • maxActive 最大连接数:池子里最多能有多少连接(上限)

  • minIdle 最小空闲连接:池子里最少保留多少空闲连接

  • maxWait 最大等待时间:拿不到连接时,最多等待多久,超时抛异常

  • 空闲连接超时:长时间不用的连接自动回收

4. 常见连接池实现

  • DBCP:Apache,老款

  • C3P0:老款,配置繁琐

  • Druid(德鲁伊,阿里):国内最常用,性能好、自带监控、防SQL注入

  • HikariCP:SpringBoot2 默认,速度最快,轻量,现在主流首选

    面试一句话:SpringBoot2默认使用HikariCP。

5. 核心API(JDBC规范:javax.sql.DataSource)

所有连接池都实现DataSource接口,核心方法:

复制代码
// 从池子获取连接
Connection conn = dataSource.getConnection();
// 使用完,不是关闭数据库,而是归还池子!
conn.close(); 

⚠️重点:连接池拿到的connection.close()不是销毁连接,是归还连接池。

6. Druid快速入门示例

Maven依赖

复制代码
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.20</version>
</dependency>

Java代码

复制代码
import com.alibaba.druid.pool.DruidDataSource;
import java.sql.Connection;

public class DruidTest {
    public static void main(String[] args) throws Exception {
        //1. 创建数据源对象(连接池)
        DruidDataSource ds = new DruidDataSource();
        //数据库配置
        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/你的库名?useSSL=false");
        ds.setUsername("root");
        ds.setPassword("你的密码");

        //连接池参数
        ds.setInitialSize(5);
        ds.setMaxActive(10);
        ds.setMinIdle(3);
        ds.setMaxWait(3000);

        //2. 获取连接(从池子里拿)
        Connection conn = ds.getConnection();
        System.out.println(conn);

        //3. 归还连接,不是销毁
        conn.close();
    }
}

7. 连接池工作流程

  1. 程序启动,初始化连接池,创建initialSize个连接放入池子

  2. 业务代码调用dataSource.getConnection()

    • 池中有空闲连接 → 直接取出

    • 无空闲连接,且当前连接数 < maxActive → 创建新连接

    • 连接已经达到maxActive → 等待maxWait时间,超时抛异常

  3. 使用完毕调用conn.close(),连接归还回池子,不关闭数据库连接

8. 对比:原生JDBC vs 连接池

  • 原生JDBC:DriverManager.getConnection(),每次新建连接,close销毁

  • 连接池:DataSource.getConnection(),复用连接,close归还

9. 面试考点

Q:为什么要用连接池? A:创建数据库连接开销巨大,连接池预先创建、复用连接,提升性能,控制连接数量保护数据库。
Q:conn.close()在连接池里做了什么? A:不是关闭数据库连接,把连接归还到连接池,等待下次复用。
Q:HikariCP和Druid区别? A:HikariCP性能极高,轻量,SpringBoot默认;Druid阿里出品,自带监控页面,防注入,功能多。

10. 常见坑

  1. 忘记归还连接:连接泄漏,池子连接耗尽,后面拿不到连接

  2. maxActive设置过大,数据库扛不住

  3. 连接长时间空闲,数据库单方面断开连接,使用时报错


相关推荐
梦帮科技2 小时前
一次性会员支付系统的可靠性设计:幂等、金额校验、Webhook 与链上确认
人工智能·神经网络·mysql·区块链·建造者模式·合成复用原则·加密货币
初願致夕霞2 小时前
MySQL_事务(MVCC机制详解)
数据库·mysql
geovindu2 小时前
sql: Data Modeling Patterns using mysql
sql·mysql·设计模式·数据库开发
今年下半年2 小时前
mysql数据库备份详细操作流程
学习·mysql
Kamille Bidan2 小时前
平台核心业务表结构设计
mysql·heidisql
梦帮科技3 小时前
从提示词到可复现音乐工作流:RNOISE 2.0 的 Prompt Engineering 架构
人工智能·python·mysql·ci/cd·架构·node.js·numpy
军训猫猫头4 小时前
C# 封装 MySQL 自动写入与查询工具类(基于 MySqlConnector)
mysql·c#·.net·wpf
呆萌很16 小时前
MySQL 数据库和表的管理操作(命令行)
数据库·mysql
毕业设计70317 小时前
(免费领源码)基于Python的博物馆研学活动管理系统的设计与实现22724- java、PHP、python、C#、小程序、大数据、单片机、网络工程等)
python·mysql·随机森林·pycharm·django·flask·推荐算法