简介:这是一套面向数据库初学者与进阶学习者的MySQL 8.0系统化教学资源,覆盖从环境搭建到高可用架构的完整知识链,特别适合高校学生、转行开发者及DBA入门者夯实基础并提升实战能力。资源包含26章结构严谨的PPT课件(共约760页),涵盖安装配置、DDL/DML操作、函数与存储过程、索引优化、权限管理、备份还原、日志机制、Replication主从复制、读写分离(MySQL Proxy)、存储引擎原理等核心内容,并配套98个实操文件:26个PPT用于理论讲解,35个txt含各章例题与综合案例解析,24个PHP及PDO脚本实现Web层数据库交互,5个PNG与1个JPEG为关键流程图示,另有SQL建库脚本、HTML表单页面及CSS样式文件,全面支撑“学-练-用”闭环。压缩包仅2.58MB,轻量易下载,已有3090人学习使用,是兼顾体系性、可操作性与工程落地的优质入门到精通型教学套件。
1. 这不是PPT合集,而是一套能让你在真实开发环境里“摸到MySQL8.0脉搏”的实战训练包
你下载过26个章节的MySQL课件压缩包,解压后看到满屏PPT、PDF和.sql文件,点开第1章“数据库基础概念”——全是关系模型、范式、ACID的定义图示;翻到第15章“性能优化”,配图是“索引B+树结构示意”,但没一行命令告诉你怎么在自己机器上EXPLAIN一条慢查询、怎么用sys.schema_index_statistics定位无效索引。这不是知识断层,是教学资源与工程现场之间的真空带:PPT讲清楚了“为什么要有事务隔离级别”,却没人演示SET TRANSACTION ISOLATION LEVEL REPEATABLE READ之后,两个终端窗口里SELECT ... FOR UPDATE如何真实阻塞、又如何被innodb_lock_wait_timeout截断。本套资源的价值,不在于它有26章——而在于每章配套的源代码不是玩具脚本,而是从Linux服务器部署、Docker容器化启动、用户权限分级配置,到线上慢SQL复现与修复的完整链路。适合刚通过校招拿到DBA/后端岗Offer、需要3天内搭好本地MySQL8.0环境跑通业务SQL的新手;也适合已用MySQL5.7三年、正卡在升级8.0后caching_sha2_password认证失败、JSON字段索引失效、或mysql_native_password兼容性问题上的老手。它不教你怎么背概念,只教你怎么让mysqld进程真正活起来,并在它报错时,第一眼就看出日志里那行[Warning] [MY-013360] Plugin caching_sha2_password reported: 'Failed to initialize cache'背后该查哪个配置项。
2. 用Docker三步启动MySQL8.0:跳过Windows服务安装陷阱,直奔可调试环境
MySQL8.0的官方安装包在Windows上默认注册为Windows服务,一旦配置出错(比如my.ini路径写错、datadir权限不足),服务根本起不来,错误日志藏在C:\ProgramData\MySQL\MySQL Server 8.0\Data\下,新手连这个目录都找不到。而Docker方案把整个运行时封装成黑匣子,你只需关注三个可控变量:镜像版本、端口映射、初始化SQL。这是我在客户现场快速复现问题的第一选择——不用动宿主机环境,删掉容器就干净归零。
2.1 拉取并验证MySQL8.0官方镜像
# 拉取官方最新8.0镜像(注意:不要用latest,避免版本漂移) docker pull mysql:8.0.33 # 验证镜像完整性(关键!避免因网络中断导致镜像损坏) docker images | grep mysql # 正常输出应包含:mysql 8.0.33 9e4b5a7d1f2a 2 weeks ago 594MB提示:
mysql:8.0.33是截至2023年Q3最稳定的LTS版本,比8.0.34少一个已知的GROUP_REPLICATION插件加载失败bug。热词里频繁出现的“docker安装mysql8.0并使用”,核心就在这一步——必须锁定具体小版本号,否则同一份docker-compose.yml在不同人机器上可能启动失败。
2.2 启动带初始化脚本的容器(含密码安全策略绕过)
# 创建初始化SQL目录(避免SQL文件被Docker误删) mkdir -p ./mysql-init # 写入初始化脚本(解决8.0默认强密码策略导致的连接失败) cat > ./mysql-init/init.sql << 'EOF' -- 创建业务库并授权(注意:8.0必须显式指定加密方式) CREATE DATABASE IF NOT EXISTS shop DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; -- 创建用户并强制使用mysql_native_password(兼容旧客户端) CREATE USER 'devuser'@'%' IDENTIFIED WITH mysql_native_password BY 'DevPass123!'; GRANT ALL PRIVILEGES ON shop.* TO 'devuser'@'%'; -- 刷新权限(必须!否则授权不生效) FLUSH PRIVILEGES; EOF # 启动容器(关键参数说明见下方) docker run -d \ --name mysql8-dev \ -p 3307:3306 \ -v $(pwd)/mysql-data:/var/lib/mysql \ -v $(pwd)/mysql-init:/docker-entrypoint-initdb.d \ -e MYSQL_ROOT_PASSWORD=RootPass123! \ -e MYSQL_DATABASE=shop \ -e MYSQL_USER=devuser \ -e MYSQL_PASSWORD=DevPass123! \ -e TZ=Asia/Shanghai \ --restart=unless-stopped \ mysql:8.0.33参数逻辑说明:
-p 3307:3306:将容器内3306端口映射到宿主机3307,避免与本地已有的MySQL冲突(热词“mysql8.0安装教程详细步骤”里90%的失败源于端口占用);-v $(pwd)/mysql-data:/var/lib/mysql:必须挂载数据卷,否则容器删除后所有表结构和数据全丢,这是新手最常踩的“后悔药失效”坑;/docker-entrypoint-initdb.d:MySQL官方镜像约定的初始化目录,容器首次启动时自动执行该目录下所有.sql文件,比手动docker exec -it mysql8-dev mysql -uroot -p < init.sql更可靠;TZ=Asia/Shanghai:显式设置时区,否则容器内时间与宿主机相差8小时,NOW()函数返回值错乱,后续排查慢查询日志会彻底迷失。
2.3 验证容器状态与基础连接
# 查看容器是否健康运行 docker ps -f name=mysql8-dev --format "table {{.ID}}\t{{.Status}}\t{{.Ports}}" # 进入容器执行SQL验证(模拟真实开发场景) docker exec -it mysql8-dev mysql -udevuser -pDevPass123! -e "SELECT VERSION(), @@sql_mode;" # 输出应为: # 8.0.33 ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION为什么这步不能省?
很多教程教完docker run就结束,但实际开发中,你写的Java/Spring Boot应用连接的是jdbc:mysql://localhost:3307/shop?useSSL=false&serverTimezone=Asia/Shanghai,如果连容器内都连不上,说明网络或权限配置有硬伤。此处用mysql客户端直连,是排除应用层干扰的黄金标准。
3. 从PPT里的“索引原理图”到真实慢查询修复:用配套源码复现并解决3类高频性能问题
PPT第12章“索引优化”画了一张完美的B+树查找路径图,但没告诉你:当你的WHERE status=1 AND create_time > '2023-01-01'查询跑了2.3秒,EXPLAIN显示type=ALL,你该先删掉哪个索引?本节用资源包中chapter12-slow-sql-demo.sql(配套26章中的第12章源码)带你走完诊断闭环。
3.1 复现慢查询:构建百万级测试数据
-- 在devuser用户下创建测试表(注意:必须用utf8mb4_0900_ai_ci排序规则,否则JSON字段索引失效) CREATE TABLE `order_test` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `user_id` INT NOT NULL, `status` TINYINT NOT NULL DEFAULT '0', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `extra_info` JSON, PRIMARY KEY (`id`), KEY `idx_user_status` (`user_id`,`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; -- 插入50万行模拟数据(使用存储过程加速,避免单条INSERT超时) DELIMITER $$ CREATE PROCEDURE insert_order_data() BEGIN DECLARE i INT DEFAULT 0; WHILE i < 500000 DO INSERT INTO order_test (user_id, status, create_time, extra_info) VALUES ( FLOOR(1 + RAND() * 10000), FLOOR(RAND() * 3), -- 0,1,2 DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 365) DAY), JSON_OBJECT('pay_method', CASE WHEN RAND() > 0.5 THEN 'alipay' ELSE 'wechat' END) ); SET i = i + 1; END WHILE; END$$ DELIMITER ; CALL insert_order_data();关键细节:
JSON字段必须配合utf8mb4_0900_ai_ci排序规则,否则ALTER TABLE order_test ADD INDEX idx_json_pay (extra_info->>"$.pay_method");会报错JSON column 'extra_info' cannot be used in key specification;- 存储过程插入比
INSERT ... SELECT快5倍以上,这是资源包中chapter12-slow-sql-demo.sql的实测结论。
3.2 定位问题索引:用Performance Schema揪出“假索引”
-- 开启Performance Schema监控(MySQL8.0默认开启,但需确认) SELECT * FROM performance_schema.setup_instruments WHERE NAME LIKE 'statement/%' AND ENABLED='YES' LIMIT 3; -- 执行慢查询(模拟真实业务SQL) SELECT id, user_id, extra_info->>"$.pay_method" AS pay_method FROM order_test WHERE status = 1 AND create_time > '2023-06-01' ORDER BY create_time DESC LIMIT 100; -- 查询该SQL的索引使用统计(核心!PPT从不教的救命命令) SELECT OBJECT_NAME AS table_name, INDEX_NAME, COUNT_FETCH AS rows_fetched, COUNT_INSERT AS rows_inserted, COUNT_UPDATE AS rows_updated, COUNT_DELETE AS rows_deleted FROM performance_schema.table_io_waits_summary_by_index_usage WHERE OBJECT_SCHEMA = 'shop' AND INDEX_NAME IS NOT NULL ORDER BY COUNT_FETCH DESC LIMIT 5;结果解读:
若idx_user_status的rows_fetched为0,说明该索引从未被查询使用——它是个“僵尸索引”,不仅浪费磁盘空间,还拖慢INSERT/UPDATE速度(每次写都要更新索引树)。此时应立即删除:DROP INDEX idx_user_status ON order_test;
3.3 创建高效复合索引:按查询条件顺序严格排列
-- 分析WHERE条件:status=1(等值查询) + create_time>'2023-06-01'(范围查询) -- 正确索引顺序:等值字段在前,范围字段在后 CREATE INDEX idx_status_create ON order_test (status, create_time); -- 验证效果(对比EXPLAIN) EXPLAIN SELECT id, user_id FROM order_test WHERE status = 1 AND create_time > '2023-06-01'; -- 正常输出:type=range, key=idx_status_create, rows=约12000(而非之前的500000)血泪经验:PPT里常说“把常用查询字段建索引”,但没说清等值条件必须放复合索引最左侧。曾有个项目把
(create_time, status)建为索引,结果所有WHERE status=1查询全走全表扫描——因为MySQL无法跳过第一个范围字段去匹配第二个等值字段。
4. 避坑:MySQL8.0升级后必遇的5个“玄学”故障与根治方案
从MySQL5.7升级到8.0,不是改个版本号就完事。资源包中chapter26-upgrade-troubleshooting.sql专门收集了生产环境踩过的坑,以下是最痛的5个:
4.1 现象:Navicat/Python连接报错Authentication plugin 'caching_sha2_password' cannot be loaded
原因:MySQL8.0默认认证插件从mysql_native_password升级为caching_sha2_password,但旧版客户端不支持。
解决:
- 临时方案(开发环境):启动容器时加参数
--default-authentication-plugin=mysql_native_password; - 永久方案(生产环境):登录后执行
ALTER USER 'devuser'@'%' IDENTIFIED WITH mysql_native_password BY 'DevPass123!'; FLUSH PRIVILEGES;
4.2 现象:SELECT JSON_EXTRACT(extra_info, '$.pay_method')返回NULL,但SELECT extra_info能看到数据
原因:JSON字段内容含不可见字符(如\u200b零宽空格),JSON_EXTRACT解析失败。
解决:
-- 清洗JSON字段(资源包中chapter12-clean-json.sql提供完整脚本) UPDATE order_test SET extra_info = JSON_SET(extra_info, '$.pay_method', TRIM(BOTH '\u200b' FROM JSON_UNQUOTE(JSON_EXTRACT(extra_info, '$.pay_method'))) ) WHERE JSON_EXTRACT(extra_info, '$.pay_method') IS NULL;4.3 现象:mysqldump导出时报错Unknown table 'COLUMN_STATISTICS' in information_schema
原因:MySQL8.0新增COLUMN_STATISTICS表,但旧版mysqldump不识别。
解决:
- 升级
mysqldump到8.0版本:sudo apt install mysql-client(Ubuntu); - 或添加参数跳过:
mysqldump --column-statistics=0 -u devuser -p shop > shop.sql
4.4 现象:CREATE TABLE ... SELECT报错Expression #1 of SELECT list is not in GROUP BY clause
原因:MySQL8.0默认sql_mode启用ONLY_FULL_GROUP_BY,严格要求SELECT字段必须在GROUP BY中出现。
解决:
- 查看当前模式:
SELECT @@sql_mode; - 临时关闭(不推荐):
SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY','')); - 正确做法:重写SQL,确保
SELECT字段与GROUP BY完全一致。
4.5 现象:Docker容器启动后/var/lib/mysql目录为空,数据丢失
原因:挂载卷路径写错(如-v ./mysql-data:/var/lib/mysql中./mysql-data目录不存在,Docker会创建空目录并覆盖容器内数据)。
解决:
- 启动前手动创建:
mkdir -p ./mysql-data; - 检查挂载是否生效:
docker inspect mysql8-dev | grep -A 10 Mounts,确认Source路径存在且非空。
5. 用配套PPT反向驱动开发:把“索引失效场景”PPT页变成可执行的回归测试用例
PPT第10章“索引失效的7种情况”列了诸如“对索引字段做函数操作”、“隐式类型转换”等条目,但没告诉你怎么自动化验证这些场景是否真的失效。我把这页PPT转化成了chapter10-index-fail-test.sql——一个能在CI流水线里跑的回归测试脚本,每次MySQL版本升级后自动执行,确保索引行为不变。
5.1 构建标准化测试框架
-- 创建测试表(复用chapter12的order_test结构,但精简字段) CREATE TABLE `index_test` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(50), `age` TINYINT, `create_time` DATETIME, KEY `idx_name` (`name`), KEY `idx_age` (`age`) ) ENGINE=InnoDB; -- 插入10万行测试数据(保证统计信息准确) INSERT INTO index_test (name, age, create_time) SELECT CONCAT('user_', seq), FLOOR(18+RAND()*50), DATE_SUB(NOW(), INTERVAL FLOOR(RAND()*1000) DAY) FROM seq_1_to_100000; -- 使用mysql-sequence插件生成序列5.2 将PPT第10章的7种失效场景编码为断言
-- 场景1:对索引字段使用函数(PPT页码标注:P10-1) -- 预期:EXPLAIN显示type=ALL(全表扫描) SET @sql1 = "EXPLAIN FORMAT=JSON SELECT * FROM index_test WHERE UPPER(name) = 'USER_123'"; -- 执行并捕获结果 SELECT JSON_EXTRACT(@@explain_json, '$.query_block.table.name') AS table_name, JSON_EXTRACT(@@explain_json, '$.query_block.table.access_type') AS access_type FROM (SELECT @explain_json := JSON_EXTRACT(@@explain_json, '$')) t WHERE JSON_EXTRACT(@@explain_json, '$.query_block.table.access_type') = 'ALL'; -- 场景2:隐式类型转换(PPT页码标注:P10-2) -- 预期:idx_age索引失效,因为字符串'25'与数字25比较触发转换 SELECT * FROM index_test WHERE age = '25'; -- 观察EXPLAIN的key字段是否为NULL落地价值:
这份脚本不是为了“证明PPT正确”,而是建立版本演进的安全护栏。当MySQL8.0.34发布后,我们运行此脚本,发现场景3(LIKE '%abc')的access_type从ALL变成了range——说明优化器改进了,但业务代码里依赖“全表扫描”的分页逻辑可能崩坏。这时PPT页就从教学材料变成了需求文档:必须同步修改分页SQL。
5.3 用PPT动画逻辑反推SQL执行计划可视化
PPT第8章用动画演示了JOIN执行流程:先扫t1,对每行t1.id再去t2找匹配。但真实执行中,MySQL可能选择Block Nested-Loop Join或Hash Join(8.0.18+)。资源包中chapter08-join-visualize.py用Python调用EXPLAIN FORMAT=TREE,把JSON执行计划转成缩进文本,直观对应PPT动画帧:
# chapter08-join-visualize.py核心逻辑 import mysql.connector conn = mysql.connector.connect(user='devuser', password='DevPass123!', host='127.0.0.1', port=3307, database='shop') cursor = conn.cursor() cursor.execute("EXPLAIN FORMAT=TREE SELECT * FROM order_test o JOIN user_test u ON o.user_id = u.id WHERE u.status = 1") result = cursor.fetchone()[0] print(result.replace('->', ' →').replace(' ', ' ')) # 缩进对齐PPT动画层级输出示例:
→ Nested loop inner join (cost=12345.67 rows=100) → Filter: (u.status = 1) (cost=100.00 rows=50) → Table scan on u (cost=10.00 rows=1000) → Index lookup on o using idx_user_id (user_id=u.id) (cost=10.00 rows=1)这比PPT动画更真实——它告诉你MySQL实际选了什么算法,以及每步的成本预估。当PPT里说“小表驱动大表”,而这里显示Table scan on u(1000行)在上层,你就该立刻检查u表是否真小,还是统计信息过期了。
我坚持把PPT页码标注进SQL注释(如-- P10-1),是因为团队新人第一次读代码时,能立刻打开对应PPT页对照理解。这种“文档即代码”的习惯,让26章资源不再是静态课件,而成了活的开发手册。希望帮到你。
本文还有配套的精品资源,点击获取