这个目录现在只保留一套正式的学习材料,统一放在 lessons/ 下面。
命名规则统一为:
- 所有课程统一使用目录:
lesson01_具体内容/ - 每个课程目录里至少包含课程代码和
README.md - 后面复习时,优先先看每节课目录里的
README.md
后面复习时,优先看 lessons/,不要再看早期散落在根目录里的练习文件。
- 已完成:第 1 课 到 第 96 课(第一阶段完成)
- 下一课建议:进入第二阶段,优先学习 Spring Security / JWT、Redis、MyBatis-Plus 和更完整的项目实战
如果你现在不想从头翻,可以直接按这个入口走:
- 想补语法基础:先看第 1~15 课
- 想补 Spring Boot 接口:先看第 18~33 课
- 想补数据库主线:先看第 34~62 课
- 想补索引、分页优化、任务系统:先看第 63~87 课
- 想补接口工程化收口:先看第 88~96 课
- 想快速回到综合项目:直接看
lessons/lesson95_mini_project_review/ - 想做第一阶段自测:直接看
lessons/lesson96_phase1_final_review/phase1_review_checklist.md - 想开始第二阶段:直接看
lessons/lesson96_phase1_final_review/phase2_learning_roadmap.md
建议你后面固定按这个顺序学习或回顾:
- 先看根目录这个
README.md,确认当前学到哪一课 - 再进入对应课的目录,先看该课的
README.md - 最后再看代码,并按课程里的命令运行
这样不会在一堆文件里来回找。
当前最重要的目录是:
lessons/
这个目录里保存了每一节课的正式版本代码,后续回顾、练习、继续学习都从这里开始。
如果你后面不是按课号回顾,而是按主题回顾,可以按下面看:
- 第 1~5 课:Java 基础语法、方法、对象、List、Map
- 第 6~15 课:文件拆分、包、封装、输入、异常、小项目、文件读写
- 第 16~17 课:Maven 工程化基础
- 第 18~27 课:Spring Boot 接口、参数、JSON、校验、分层、异常处理
- 第 28~33 课:Spring Boot 配置体系
- 第 34~41 课:数据库基础、MySQL、SQL CRUD、表结构设计、建库建表、字段约束、查询进阶
- 第 42~46 课:JDBC 入门、JDBC CRUD、JDBC 事务、JDBC 分层、JDBC 工具类抽取
- 第 47~50 课:Spring Boot 数据访问入门、Spring Boot 数据 CRUD、事务管理、条件查询与分页
- 第 51~62 课:MyBatis 入门、动态 SQL、CRUD、分页查询、动态更新、resultMap、字段映射、多表查询、嵌套对象、一对多、分步查询、N+1 问题、查询优化入门
- 第 63~72 课:SQL 索引与 EXPLAIN、索引失效、排序分页优化、深分页优化、count 代价、分页接口整体优化、复杂筛选和动态 SQL 的索引取舍、搜索排序分页的接口设计
- 第 73~76 课:后台表格接口能力分层、导出异步化、大结果集分批处理、批处理任务与在线接口资源隔离
- 第 77~87 课:后台作业体系、任务幂等、并发领取、超时回收、重试退避、死信补偿、调度器与 worker 链路、任务日志与可观测性、告警与人工介入、重复投递防护、任务系统整体复盘
- 第 88~91 课:DTO / VO / Entity 分层、统一分页返回结构、文件上传下载、登录校验与 Token 基础
- 第 92~94 课:接口联调、自动化测试、打包运行与多环境配置
- 第 95~96 课:综合小项目复盘、第一阶段总复习与第二阶段路线图
这样你后面查漏补缺会更快。
如果你后面想按“学习阶段”推进,而不是只按课号推进,可以按下面这个路线走:
- 第 1~5 课
- 目标:
- 先熟悉变量、类型、方法、类、对象
- 理解
List和Map - 建立最基础的 Java 代码阅读能力
这一阶段结束后,你至少应该能看懂最简单的 Java 小程序。
- 第 6~15 课
- 目标:
- 理解拆文件、包、封装
- 学会输入处理、异常处理
- 能写一个最小命令行管理系统
- 开始接触文件保存
这一阶段结束后,你应该能写出一个小型命令行项目,而不只是零散语法练习。
- 第 16~17 课
- 目标:
- 理解 Maven 是什么
- 理解
pom.xml - 理解编译、打包、
target/
这一阶段结束后,你应该知道 Java 项目为什么不能永远只靠 javac 裸编译。
- 第 18~27 课
- 目标:
- 学会写最小 Web 接口
- 学会接收查询参数和请求体
- 学会返回 JSON
- 学会参数校验、分层、统一返回结构
- 学会全局异常处理
这一阶段结束后,你已经具备最基础的 Spring Boot 接口开发能力。
- 第 28~33 课
- 目标:
- 理解配置与代码分离
- 学会
@Value - 学会 Profiles 多环境配置
- 学会
@ConfigurationProperties - 学会配置校验和 YAML
- 把配置体系串成一张完整脑图
这一阶段结束后,你对 Spring Boot 配置这条线应该已经比较清楚。
- 第 34~62 课
- 目标:
- 先理解数据库基础概念、表设计和 SQL
- 再进入 JDBC CRUD、事务、分层、工具类抽取
- 再进入 Spring Boot 数据访问和 MyBatis 基础能力
这一阶段结束后,你应该已经能把“接口 + 数据库”真正连起来理解。
- 第 63~87 课
- 目标:
- 理解索引、EXPLAIN、分页优化、动态 SQL 取舍
- 理解后台表格接口、导出、大结果集处理
- 理解任务系统里的调度、执行、重试、死信、补偿、观测
这一阶段结束后,你会开始从“会写数据接口”进入“会考虑性能和系统链路”。
- 第 88~96 课
- 目标:
- 理解 DTO / VO / Entity 分层
- 理解统一分页返回结构
- 理解文件上传下载、登录 Token、接口联调、自动化测试
- 理解打包运行、配置切换、综合小项目结构
- 完成第一阶段总复习和路线规划
这一阶段结束后,你就完成了第一阶段的 Java 后端入门闭环。
如果你已经学到第 96 课,可以把第一阶段的目标理解成:
- 会写最基础的 Java 和 Spring Boot 代码
- 会做最基础的数据库开发
- 会做最基础的登录、分页、分层、联调、测试、打包
- 能看懂一个最小后端项目是怎么组织起来的
第一阶段结束后,建议不要再无目的地补零散知识,优先按这个顺序进入第二阶段:
- Spring Security / JWT / 权限控制
- Redis 基础与登录态 / 缓存场景
- MyBatis-Plus 和数据库设计进阶
- 做一个更完整的小项目实战
- 再逐步进入 Docker、Linux 部署、消息队列、日志监控
这样衔接会最顺,不容易出现“前面学过,但串不到真实项目里”的情况。
先进入项目根目录:
cd /Users/leon/Desktop/aiTest/java例如第 1 课:
javac lessons/lesson01_hello_java/lesson01_hello_java.java
java lessons.lesson01_hello_java.lesson01_hello_java例如第 6 课:
javac lessons/lesson06_multi_file/*.java
java lessons.lesson06_multi_file.main_app例如第 7 课:
javac lessons/lesson07_package_import/model/product.java lessons/lesson07_package_import/app/product_app.java
java lessons.lesson07_package_import.app.product_app补充两个统一规则:
- 每一课优先以该课目录里的
README.md为准 - Spring Boot / Maven 课程优先进入课程目录后再执行
mvn命令
- 目录:
lessons/lesson01_hello_java/ - 文件:
lessons/lesson01_hello_java/lesson01_hello_java.javalessons/lesson01_hello_java/README.md
- 学习内容:
- 变量
- 基本类型
- 字符串
System.out.printlniffor
- 你已经练习过:
- 修改
name - 修改
age - 把循环从
1..3改成1..5
- 修改
- 回顾重点:
- Java 是强类型语言
- 每个变量都要先写类型
main是程序入口
- 目录:
lessons/lesson02_class_and_method_demo/ - 文件:
lessons/lesson02_class_and_method_demo/lesson02_class_and_method_demo.javalessons/lesson02_class_and_method_demo/README.md
- 学习内容:
- 方法
- 返回值
- 类
- 对象
- 构造函数
- 你已经接触到:
add(int a, int b)new lesson02_person("Leon", 29)
- 建议回顾:
- 方法和 JS 函数的区别
- 类和对象的关系
- 构造函数为什么会在
new的时候自动执行
- 目录:
lessons/lesson03_control_flow_demo/ - 文件:
lessons/lesson03_control_flow_demo/lesson03_control_flow_demo.javalessons/lesson03_control_flow_demo/README.md
- 学习内容:
if / else if / elsereturnboolean- 对象作为方法参数
- 你已经练习过:
- 修改分数
- 观察等级和是否及格的变化
- 回顾重点:
void方法不返回值String、boolean这类返回值要和方法声明保持一致- Java 会根据条件分支返回不同结果
- 目录:
lessons/lesson04_list_demo/ - 文件:
lessons/lesson04_list_demo/lesson04_list_demo.javalessons/lesson04_list_demo/README.md
- 学习内容:
ListArrayList- 增强
for - 统计数量
- 找最大值
- 你已经接触到:
students.add(...)for (lesson04_student_item student : students)countPassedStudents(...)findTopStudent(...)
- 建议练习:
- 增加更多学生
- 写
countExcellentStudents - 写
printPassedStudents
- 目录:
lessons/lesson05_map_demo/ - 文件:
lessons/lesson05_map_demo/lesson05_map_demo.javalessons/lesson05_map_demo/README.md
- 学习内容:
MapHashMapputgetcontainsKeykeySet
- 你已经实现过:
containsUserprintAllUsernames
- 回顾重点:
Map很像前端里的对象字典- 查不到值时要考虑
null containsKey是判断 key 是否存在的常用方法
- 目录:
lessons/lesson06_multi_file/ - 文件:
lessons/lesson06_multi_file/main_app.javalessons/lesson06_multi_file/user_service.javalessons/lesson06_multi_file/user_info.javalessons/lesson06_multi_file/README.md
- 学习内容:
- 一个功能拆成多个类
- 入口类
- 数据类
- 业务类
- 当前结构说明:
main_app负责启动程序user_info负责描述用户数据user_service负责用户相关逻辑
- 回顾重点:
- Java 项目通常不是所有代码都写在一个文件里
- “数据”和“业务逻辑”要分开
- 目录:
lessons/lesson07_package_import/ - 文件:
lessons/lesson07_package_import/model/product.javalessons/lesson07_package_import/app/product_app.javalessons/lesson07_package_import/README.md
- 学习内容:
packageimport- 跨包引用
- 当前重点:
product在model包product_app在app包- 因为不在同一个包里,所以必须
import
- 回顾重点:
- 同包类通常可以直接用
- 不同包类通常需要
import java.lang里的类是默认可用的
- 目录:
lessons/lesson08_encapsulation_demo/ - 文件:
lessons/lesson08_encapsulation_demo/lesson08_encapsulation_demo.javalessons/lesson08_encapsulation_demo/README.md
- 学习内容:
private- 封装
- getter
- setter
- 在 setter 中做数据校验
- 当前重点:
- 字段不要直接暴露在外部
- 外部代码通过方法读取和修改对象数据
- setter 里可以限制非法值进入对象
- 你会看到的内容:
private String username;getUsername()setName(...)setAge(...)
- 回顾重点:
private是“只能在当前类内部访问”- getter 用来读取字段
- setter 用来修改字段
- 封装的核心不是语法,而是“把数据保护起来”
- 目录:
lessons/lesson09_array_and_string_demo/ - 文件:
lessons/lesson09_array_and_string_demo/lesson09_array_and_string_demo.javalessons/lesson09_array_and_string_demo/README.md
- 学习内容:
- 数组
String[] length- 遍历数组
- 字符串拼接
trim()toUpperCase()contains()length()
- 数组
- 当前重点:
- 数组适合保存固定数量的数据
- 字符串在 Java 里有很多常用方法
数组.length和字符串.length()写法不一样
- 你会看到的内容:
String[] names = {"Leon", "Alice", "Bob"};for (String name : names)text.trim()text.contains("back")
- 回顾重点:
- 数组是最基础的集合结构
- 字符串处理是写业务代码的高频操作
- 以后做输入校验、接口参数处理时会经常用到
- 目录:
lessons/lesson10_scanner_demo/ - 文件:
lessons/lesson10_scanner_demo/lesson10_scanner_demo.javalessons/lesson10_scanner_demo/README.md
- 学习内容:
ScannerSystem.innextLine()- 把输入的字符串转成整数
- 根据用户输入做分支判断
- 当前重点:
- 程序不再只是运行固定代码,而是开始和用户交互
Scanner scanner = new Scanner(System.in);表示从终端读取输入nextLine()会读取一整行文本Integer.parseInt(...)可以把字符串转成int
- 你会看到的内容:
- 输入姓名
- 输入年龄
- 输入城市
- 程序根据年龄判断是否成年
- 回顾重点:
Scanner是命令行交互程序的基础- 初学时优先使用
nextLine(),更稳定,少踩坑 - 数字输入本质上也是先读字符串,再转类型
- 目录:
lessons/lesson11_menu_demo/ - 文件:
lessons/lesson11_menu_demo/lesson11_menu_demo.javalessons/lesson11_menu_demo/README.md
- 学习内容:
while- 布尔变量控制循环
- 菜单选择
- 多次输入
- 根据选项执行不同逻辑
- 当前重点:
- 程序不再只执行一次,而是可以持续运行
- 用户输入
0时退出程序 - 用户输入不同菜单项时会进入不同分支
- 你会看到的内容:
- 选项 1:打招呼
- 选项 2:两个数字相加
- 选项 3:显示城市
- 选项 0:退出程序
- 回顾重点:
while (running)是命令行菜单程序的基础结构- 菜单本质上就是“循环 + 输入 + 条件分支”
- 这是写命令行小工具的常见起点
- 目录:
lessons/lesson12_try_catch_demo/ - 文件:
lessons/lesson12_try_catch_demo/lesson12_try_catch_demo.javalessons/lesson12_try_catch_demo/README.md
- 学习内容:
trycatchNumberFormatException- 输入错误时避免程序直接崩溃
- 当前重点:
- 用户输入不一定总是合法
- 把可能报错的代码放进
try - 出错后在
catch里给出提示
- 你会看到的内容:
- 读取两个输入
- 用
Integer.parseInt(...)转数字 - 输入非法时打印错误提示
- 回顾重点:
- 异常处理是让程序更稳的基础手段
try/catch不会消灭错误,但可以接住错误- 写交互程序时,异常处理非常常见
- 目录:
lessons/lesson13_student_manager_demo/ - 文件:
lessons/lesson13_student_manager_demo/lesson13_student_manager_demo.javalessons/lesson13_student_manager_demo/README.md
- 学习内容:
List- 对象列表管理
Scannerwhiletry/catch- 菜单程序
- 小项目结构拆方法
- 当前重点:
- 把前面学过的内容组合到一个真实小程序里
- 菜单负责选择功能
- 方法负责处理具体逻辑
List负责存储学生数据
- 你会看到的功能:
- 添加学生
- 查看全部学生
- 查看及格学生
- 查看最高分学生
- 按姓名搜索学生
- 按姓名删除学生
- 退出程序
- 回顾重点:
- 真正写程序时,知识点通常是组合使用的
- 这已经是一个最小的命令行 CRUD 风格程序
- 这个版本已经加入了
city字段 - 这个版本已经把学生字段改成了
private并通过 getter / setter 访问 - 后面可以继续把它改成更完整的小项目
- 目录:
lessons/lesson14_student_manager_file_demo/ - 文件:
lessons/lesson14_student_manager_file_demo/lesson14_student_manager_file_demo.javalessons/lesson14_student_manager_file_demo/lesson14_students.txtlessons/lesson14_student_manager_file_demo/README.md
- 学习内容:
PathFiles.writeFiles.readAllLinesIOException- 把对象数据写入文本文件
- 从文本文件恢复对象数据
- 当前重点:
- 程序数据不再只存在内存里
- 可以把学生列表保存到本地文件
- 下次运行时可以再从文件读回来
- 你会看到的功能:
- 添加学生
- 查看全部学生
- 保存到
lessons/lesson14_student_manager_file_demo/lesson14_students.txt - 从文件读取数据
- 查看最高分学生
- 回顾重点:
- 文件读写是命令行程序走向“真实可用”的关键一步
Files.write(...)负责写文件Files.readAllLines(...)负责读文件- 读写文件时通常要处理
IOException
- 目录:
lessons/lesson15_student_manager/ - 文件:
lessons/lesson15_student_manager/main_app.javalessons/lesson15_student_manager/student.javalessons/lesson15_student_manager/student_service.javalessons/lesson15_student_manager/student_file_service.javalessons/lesson15_student_manager/README.md
- 学习内容:
- 多文件协作
- 数据类
- 业务类
- 文件服务类
- 主程序入口
- 当前重点:
main_app负责菜单和流程student负责描述学生数据student_service负责内存中的学生管理逻辑student_file_service负责文件读写
- 你会看到的功能:
- 添加学生
- 查看全部学生
- 搜索学生
- 删除学生
- 查看最高分学生
- 保存到文件
- 从文件读取
- 回顾重点:
- 代码拆文件后更接近真实项目结构
- 不同类应该各自承担明确职责
- 这是从“练习代码”走向“工程代码”的关键一步
- 目录:
lessons/lesson16_maven_demo/ - 文件:
lessons/lesson16_maven_demo/pom.xmllessons/lesson16_maven_demo/src/main/java/com/leon/App.javalessons/lesson16_maven_demo/README.md
- 学习内容:
- Maven 是什么
pom.xml是什么- Maven 默认目录结构
groupIdartifactIdversion
- 当前重点:
- Maven 是 Java 项目管理工具
pom.xml是项目配置核心- Maven 项目代码通常放在
src/main/java
- 你会看到的内容:
- 一个最小 Maven 项目结构
- 一个最小的
App.java - 一个最小的
pom.xml - 一个可实际运行的本地 Maven 命令路径
- 回顾重点:
- Maven 不是业务代码本身,而是工程化工具
- 从这一课开始,你进入 Java 工程开发阶段
- 后面学 Spring Boot 时,几乎一定会接触 Maven
- 目录:
lessons/lesson17_maven_build_notes/ - 文件:
lessons/lesson17_maven_build_notes/README.md
- 学习内容:
mvn compilemvn packagetarget/- JAR
- 当前重点:
compile负责把源码编译成.classpackage会继续生成 JARtarget/是 Maven 的构建输出目录
- 回顾重点:
package包含compile- JAR 是 Java 项目的打包产物
- 理解这些以后,再进入 Spring Boot 会顺很多
- 目录:
lessons/lesson18_spring_boot_demo/ - 文件:
lessons/lesson18_spring_boot_demo/pom.xmllessons/lesson18_spring_boot_demo/src/main/java/com/leon/demo/Application.javalessons/lesson18_spring_boot_demo/src/main/java/com/leon/demo/HelloController.javalessons/lesson18_spring_boot_demo/src/main/resources/application.propertieslessons/lesson18_spring_boot_demo/README.md
- 学习内容:
- Spring Boot 启动类
@SpringBootApplication@RestController@GetMapping- Web 项目最小结构
- 当前重点:
- Spring Boot 项目不是命令行小程序,而是 Web 应用
- 启动后会开启内置服务器
- 你可以通过浏览器访问接口
- 回顾重点:
Application.java是入口Controller是接口层- 这是 Java 后端开发真正的起点
- 目录:
lessons/lesson19_spring_request_param_demo/lessons/lesson19_spring_request_param_notes/
- 文件:
lessons/lesson19_spring_request_param_notes/README.mdlessons/lesson19_spring_request_param_demo/pom.xmllessons/lesson19_spring_request_param_demo/src/main/java/com/leon/demo/Application.javalessons/lesson19_spring_request_param_demo/src/main/java/com/leon/demo/HelloController.javalessons/lesson19_spring_request_param_demo/src/main/resources/application.properties
- 学习内容:
@RequestParam- 查询参数
- 接口方法参数绑定
- 当前重点:
- 第 19 课现在是一个独立 Spring Boot 项目
- 前端传过来的 URL 参数,后端如何接收
- 一个接口可以接收多个参数
- Spring Boot 可以自动把字符串参数转成基础类型
- 回顾重点:
http://localhost:8081/greet?name=Leonhttp://localhost:8081/intro?name=Leon&age=29&city=Shanghai- 这是写真实接口的第一步
- 目录:
lessons/lesson20_spring_resources_notes/ - 文件:
lessons/lesson20_spring_resources_notes/README.md
- 学习内容:
src/main/resourcesapplication.propertiesserver.port- 配置与代码分离
- 当前重点:
resources用来放运行时资源和配置application.properties是 Spring Boot 默认配置文件- 端口这类内容属于配置,不属于业务逻辑
- 回顾重点:
server.port=8081spring.application.name=...server.servlet.context-path=/api
- 目录:
lessons/lesson21_spring_json_demo/ - 文件:
lessons/lesson21_spring_json_demo/pom.xmllessons/lesson21_spring_json_demo/src/main/java/com/leon/demo/Application.javalessons/lesson21_spring_json_demo/src/main/java/com/leon/demo/HelloController.javalessons/lesson21_spring_json_demo/src/main/java/com/leon/demo/UserProfile.javalessons/lesson21_spring_json_demo/src/main/resources/application.propertieslessons/lesson21_spring_json_demo/README.md
- 学习内容:
- JSON 是什么
- 返回 Java 对象
- 返回
Map - Spring Boot 自动 JSON 转换
- 当前重点:
- 接口不只可以返回字符串
- 对象和
Map都可以被 Spring Boot 转成 JSON - 这是前后端联调里最常见的接口形式
- 回顾重点:
http://localhost:8082/userhttp://localhost:8082/course- getter 是对象转 JSON 的基础之一
- 目录:
lessons/lesson22_spring_request_body_demo/ - 文件:
lessons/lesson22_spring_request_body_demo/pom.xmllessons/lesson22_spring_request_body_demo/src/main/java/com/leon/demo/Application.javalessons/lesson22_spring_request_body_demo/src/main/java/com/leon/demo/UserController.javalessons/lesson22_spring_request_body_demo/src/main/java/com/leon/demo/UserCreateRequest.javalessons/lesson22_spring_request_body_demo/src/main/java/com/leon/demo/UserResponse.javalessons/lesson22_spring_request_body_demo/src/main/resources/application.propertieslessons/lesson22_spring_request_body_demo/README.md
- 学习内容:
POST请求- 请求体 JSON
@RequestBody- 请求对象和响应对象
- 当前重点:
- 真实项目里,提交数据通常不用查询参数
- Spring Boot 可以把请求体 JSON 自动绑定成 Java 对象
- 请求对象和响应对象最好有明确分工
- 回顾重点:
POST http://localhost:8083/users/create@RequestBody UserCreateRequest request- getter / setter 和无参构造方法的重要性
- 目录:
lessons/lesson23_spring_validation_demo/ - 文件:
lessons/lesson23_spring_validation_demo/pom.xmllessons/lesson23_spring_validation_demo/src/main/java/com/leon/demo/Application.javalessons/lesson23_spring_validation_demo/src/main/java/com/leon/demo/UserController.javalessons/lesson23_spring_validation_demo/src/main/java/com/leon/demo/UserCreateRequest.javalessons/lesson23_spring_validation_demo/src/main/java/com/leon/demo/UserResponse.javalessons/lesson23_spring_validation_demo/src/main/resources/application.propertieslessons/lesson23_spring_validation_demo/README.md
- 学习内容:
@Valid@NotBlank@Size@Min@Max
- 当前重点:
- 后端接收参数之后,不能直接盲目信任
- 校验规则通常定义在请求对象上
@Valid会触发这些规则生效
- 回顾重点:
POST http://localhost:8084/users/create@Valid @RequestBody UserCreateRequest request- 校验失败时默认返回
400 Bad Request
- 目录:
lessons/lesson24_spring_layered_demo/ - 文件:
lessons/lesson24_spring_layered_demo/pom.xmllessons/lesson24_spring_layered_demo/src/main/java/com/leon/demo/Application.javalessons/lesson24_spring_layered_demo/src/main/java/com/leon/demo/controller/UserController.javalessons/lesson24_spring_layered_demo/src/main/java/com/leon/demo/service/UserService.javalessons/lesson24_spring_layered_demo/src/main/java/com/leon/demo/dto/UserCreateRequest.javalessons/lesson24_spring_layered_demo/src/main/java/com/leon/demo/dto/UserResponse.javalessons/lesson24_spring_layered_demo/src/main/resources/application.propertieslessons/lesson24_spring_layered_demo/README.md
- 学习内容:
ControllerServicedto- 构造器注入
- 基础分层思维
- 当前重点:
- Controller 不要直接堆业务逻辑
- Service 专门负责业务处理
- 分层的目标是让代码可维护、可扩展
- 回顾重点:
GET http://localhost:8085/users/demoPOST http://localhost:8085/users/createUserController -> UserService -> UserResponse
- 目录:
lessons/lesson25_spring_api_response_demo/ - 文件:
lessons/lesson25_spring_api_response_demo/pom.xmllessons/lesson25_spring_api_response_demo/src/main/java/com/leon/demo/Application.javalessons/lesson25_spring_api_response_demo/src/main/java/com/leon/demo/common/ApiResponse.javalessons/lesson25_spring_api_response_demo/src/main/java/com/leon/demo/controller/UserController.javalessons/lesson25_spring_api_response_demo/src/main/java/com/leon/demo/service/UserService.javalessons/lesson25_spring_api_response_demo/src/main/java/com/leon/demo/dto/UserCreateRequest.javalessons/lesson25_spring_api_response_demo/src/main/java/com/leon/demo/dto/UserResponse.javalessons/lesson25_spring_api_response_demo/src/main/resources/application.propertieslessons/lesson25_spring_api_response_demo/README.md
- 学习内容:
- 统一返回结构
ApiResponse<T>codemessagedata
- 当前重点:
- 后端接口不一定直接裸返回业务对象
- 统一格式可以让前端更容易处理响应
- 这一步是在为后面的异常处理打基础
- 回顾重点:
GET http://localhost:8086/users/demoPOST http://localhost:8086/users/createApiResponse<UserResponse>
- 目录:
lessons/lesson26_spring_exception_handler_demo/ - 文件:
lessons/lesson26_spring_exception_handler_demo/pom.xmllessons/lesson26_spring_exception_handler_demo/src/main/java/com/leon/demo/Application.javalessons/lesson26_spring_exception_handler_demo/src/main/java/com/leon/demo/common/ApiResponse.javalessons/lesson26_spring_exception_handler_demo/src/main/java/com/leon/demo/controller/UserController.javalessons/lesson26_spring_exception_handler_demo/src/main/java/com/leon/demo/service/UserService.javalessons/lesson26_spring_exception_handler_demo/src/main/java/com/leon/demo/dto/UserResponse.javalessons/lesson26_spring_exception_handler_demo/src/main/java/com/leon/demo/exception/BusinessException.javalessons/lesson26_spring_exception_handler_demo/src/main/java/com/leon/demo/handler/GlobalExceptionHandler.javalessons/lesson26_spring_exception_handler_demo/src/main/resources/application.propertieslessons/lesson26_spring_exception_handler_demo/README.md
- 学习内容:
- 业务异常
- 全局异常处理
@RestControllerAdvice@ExceptionHandler- 错误响应统一化
- 当前重点:
- 异常处理不要散落在每个 Controller 里
- 业务异常和系统异常最好分开处理
- 统一返回结构和异常处理通常一起设计
- 回顾重点:
GET http://localhost:8087/users/find?name=LeonGET http://localhost:8087/users/find?name=TomGET http://localhost:8087/users/error
- 目录:
lessons/lesson27_spring_validation_exception_demo/ - 文件:
lessons/lesson27_spring_validation_exception_demo/pom.xmllessons/lesson27_spring_validation_exception_demo/src/main/java/com/leon/demo/Application.javalessons/lesson27_spring_validation_exception_demo/src/main/java/com/leon/demo/common/ApiResponse.javalessons/lesson27_spring_validation_exception_demo/src/main/java/com/leon/demo/controller/UserController.javalessons/lesson27_spring_validation_exception_demo/src/main/java/com/leon/demo/service/UserService.javalessons/lesson27_spring_validation_exception_demo/src/main/java/com/leon/demo/dto/UserCreateRequest.javalessons/lesson27_spring_validation_exception_demo/src/main/java/com/leon/demo/dto/UserResponse.javalessons/lesson27_spring_validation_exception_demo/src/main/java/com/leon/demo/exception/BusinessException.javalessons/lesson27_spring_validation_exception_demo/src/main/java/com/leon/demo/handler/GlobalExceptionHandler.javalessons/lesson27_spring_validation_exception_demo/src/main/resources/application.propertieslessons/lesson27_spring_validation_exception_demo/README.md
- 学习内容:
- 参数校验异常
MethodArgumentNotValidException- 全局异常处理器统一收口
- 错误信息提取
- 成功与失败格式统一
- 当前重点:
- 参数校验失败本质上也是一种接口失败
@Valid和全局异常处理通常要配合使用- 参数错误、业务错误、系统错误可以统一返回
- 回顾重点:
POST http://localhost:8088/users/create@ExceptionHandler(MethodArgumentNotValidException.class)exception.getBindingResult().getFieldErrors()
- 目录:
lessons/lesson28_spring_config_value_demo/ - 文件:
lessons/lesson28_spring_config_value_demo/pom.xmllessons/lesson28_spring_config_value_demo/src/main/java/com/leon/demo/Application.javalessons/lesson28_spring_config_value_demo/src/main/java/com/leon/demo/controller/AppController.javalessons/lesson28_spring_config_value_demo/src/main/resources/application.propertieslessons/lesson28_spring_config_value_demo/README.md
- 学习内容:
application.properties- 自定义配置
@Value- 配置与代码分离
spring.*和app.*
- 当前重点:
- 可变内容不要写死在 Java 代码里
- 配置文件负责放运行参数和业务配置
@Value可以把配置读进代码
- 回顾重点:
GET http://localhost:8089/app/infoGET http://localhost:8089/app/welcome@Value("${app.welcome-message}")
- 目录:
lessons/lesson29_spring_profiles_demo/ - 文件:
lessons/lesson29_spring_profiles_demo/pom.xmllessons/lesson29_spring_profiles_demo/src/main/java/com/leon/demo/Application.javalessons/lesson29_spring_profiles_demo/src/main/java/com/leon/demo/controller/EnvController.javalessons/lesson29_spring_profiles_demo/src/main/resources/application.propertieslessons/lesson29_spring_profiles_demo/src/main/resources/application-dev.propertieslessons/lesson29_spring_profiles_demo/src/main/resources/application-prod.propertieslessons/lesson29_spring_profiles_demo/README.md
- 学习内容:
- Profiles
application-dev.propertiesapplication-prod.propertiesspring.profiles.active- 配置覆盖
- 当前重点:
- 同一个项目在不同环境里通常要用不同配置
- profile 文件会覆盖默认配置
- 启动参数可以决定激活哪套环境配置
- 回顾重点:
GET http://localhost:8090/env/infomvn spring-boot:run -Dspring-boot.run.profiles=devmvn spring-boot:run -Dspring-boot.run.profiles=prod
- 目录:
lessons/lesson30_spring_configuration_properties_demo/ - 文件:
lessons/lesson30_spring_configuration_properties_demo/pom.xmllessons/lesson30_spring_configuration_properties_demo/src/main/java/com/leon/demo/Application.javalessons/lesson30_spring_configuration_properties_demo/src/main/java/com/leon/demo/config/AppProperties.javalessons/lesson30_spring_configuration_properties_demo/src/main/java/com/leon/demo/controller/AppController.javalessons/lesson30_spring_configuration_properties_demo/src/main/resources/application.propertieslessons/lesson30_spring_configuration_properties_demo/README.md
- 学习内容:
@ConfigurationProperties- 配置分组
prefix- 属性绑定
@Value与配置对象的区别
- 当前重点:
- 一组相关配置更适合绑定成一个对象
- 配置越多,越应该避免到处写很多个
@Value app.*这类配置很适合做前缀分组
- 回顾重点:
GET http://localhost:8091/config/infoGET http://localhost:8091/config/summary@ConfigurationProperties(prefix = "app")
- 目录:
lessons/lesson31_spring_configuration_validation_demo/ - 文件:
lessons/lesson31_spring_configuration_validation_demo/pom.xmllessons/lesson31_spring_configuration_validation_demo/src/main/java/com/leon/demo/Application.javalessons/lesson31_spring_configuration_validation_demo/src/main/java/com/leon/demo/config/AppProperties.javalessons/lesson31_spring_configuration_validation_demo/src/main/java/com/leon/demo/controller/AppController.javalessons/lesson31_spring_configuration_validation_demo/src/main/resources/application.propertieslessons/lesson31_spring_configuration_validation_demo/README.md
- 学习内容:
- 配置校验
@Validated@NotBlank@Email@Min
- 当前重点:
- 配置对象不仅能绑定值,还能做校验
- 配置错误最好在启动阶段就暴露出来
- 这一步是在提高配置的可靠性
- 回顾重点:
GET http://localhost:8092/config/check@Validatedapp.request-timeout-seconds
- 目录:
lessons/lesson32_spring_yaml_config_demo/ - 文件:
lessons/lesson32_spring_yaml_config_demo/pom.xmllessons/lesson32_spring_yaml_config_demo/src/main/java/com/leon/demo/Application.javalessons/lesson32_spring_yaml_config_demo/src/main/java/com/leon/demo/config/AppProperties.javalessons/lesson32_spring_yaml_config_demo/src/main/java/com/leon/demo/controller/AppController.javalessons/lesson32_spring_yaml_config_demo/src/main/resources/application.ymllessons/lesson32_spring_yaml_config_demo/README.md
- 学习内容:
application.yml- YAML 缩进层级
- YAML 与 properties 的区别
- 嵌套配置
- 嵌套对象绑定
- 当前重点:
- YAML 更适合表达复杂和分层配置
- 缩进就是层级,写错会影响配置解析
- 嵌套 YAML 可以映射成嵌套 Java 对象
- 回顾重点:
GET http://localhost:8093/yaml/infoGET http://localhost:8093/yaml/summaryprivate Contact contact
- 目录:
lessons/lesson33_spring_config_review_notes/ - 文件:
lessons/lesson33_spring_config_review_notes/README.md
- 学习内容:
- resources 与配置目录
- properties 与 YAML
@Value@ConfigurationProperties- Profiles
- 配置校验
- 当前重点:
- 这是一节总结课,用来把前面的配置知识串起来
- 目标不是新增语法,而是建立完整配置脑图
- 配置在真实项目里同样需要工程化思维
- 回顾重点:
- 单个配置用什么读
- 一组配置用什么读
- 不同环境怎么切换
- 配置错了怎么尽早发现
- 目录:
lessons/lesson34_database_basic_notes/ - 文件:
lessons/lesson34_database_basic_notes/README.md
- 学习内容:
- 为什么后端离不开数据库
- 数据库、表、行、列
- 关系型数据库
- MySQL 的定位
- 后端与数据库的关系
- 当前重点:
- 这是一节数据库模块的打底课
- 目标是先理解数据库解决什么问题
- 后面的 SQL、JDBC、Spring Boot 数据访问都建立在这节课上
- 回顾重点:
- 数据为什么不能只放内存
- 表、行、列分别是什么
前端 -> Controller -> Service -> 数据库
- 目录:
lessons/lesson35_mysql_intro_notes/ - 文件:
lessons/lesson35_mysql_intro_notes/README.md
- 学习内容:
- MySQL 是什么
- 数据库与数据库管理系统
- 关系型数据库
- MySQL 在后端里的位置
- 服务端与客户端
- 当前重点:
- 这是一节数据库概念继续深化课
- 目标是把 MySQL 和“数据库”这个大概念区分清楚
- 后面的 SQL、JDBC、Spring Boot 连接数据库都建立在这里
- 回顾重点:
- 数据库和 MySQL 不是一个层级的词
- 库、表、行、列分别是什么
Java 程序 -> JDBC / 框架 -> MySQL
- 目录:
lessons/lesson36_sql_basic_notes/ - 文件:
lessons/lesson36_sql_basic_notes/README.md
- 学习内容:
- SQL 是什么
SELECTINSERTUPDATEDELETE
- 当前重点:
- 这是一节数据库操作语言入门课
- 目标是先掌握最基础的 CRUD SQL
- 后面的 JDBC 和 Spring Boot 数据访问都会围绕 SQL 展开
- 回顾重点:
SELECT * FROM students WHERE age >= 25;INSERT INTO ... VALUES ...UPDATE/DELETE时要特别注意WHERE
- 目录:
lessons/lesson37_table_design_notes/ - 文件:
lessons/lesson37_table_design_notes/README.md
- 学习内容:
- 什么是表结构
- 常见字段类型
- 主键
NOT NULLDEFAULTCREATE TABLE
- 当前重点:
- 这是一节数据库设计入门课
- 目标是先看懂一张表为什么要那样设计
- 后面的 JDBC、MyBatis、Spring Boot 数据访问都会依赖这层理解
- 回顾重点:
- 一张表不只是“有几列”,而是一套字段设计规则
id往往是主键VARCHAR、INT、DECIMAL、DATETIME要按业务选择CREATE TABLE是从“操作数据”进入“定义数据结构”
- 目录:
lessons/lesson38_create_database_and_table/ - 文件:
lessons/lesson38_create_database_and_table/README.mdlessons/lesson38_create_database_and_table/lesson38_create_database_and_table.sql
- 学习内容:
CREATE DATABASEUSECREATE TABLE- 最小用户表实操
SHOW DATABASESSHOW TABLES
- 当前重点:
- 这是一节从概念进入实操的课
- 目标是让你第一次真正把“库”和“表”创建出来
- 后面的插入数据、JDBC 连接、Spring Boot 操作数据库都要基于这一步
- 回顾重点:
- 先建库,再切库,再建表
CREATE TABLE本质是在定义数据规则SHOW DATABASES和SHOW TABLES用来确认结果- 现在先求跑通,下一课再继续补更细的约束设计
- 目录:
lessons/lesson39_constraints_and_seed_data/ - 文件:
lessons/lesson39_constraints_and_seed_data/README.mdlessons/lesson39_constraints_and_seed_data/lesson39_constraints_and_seed_data.sql
- 学习内容:
AUTO_INCREMENTUNIQUEDEFAULT- 插入测试数据
- 查看约束效果
SELECT *
- 当前重点:
- 这是一节把“表结构”变得更接近真实项目的课
- 目标是让你看到主键自增、唯一约束、默认值到底在运行时起什么作用
- 后面的注册、登录、用户管理这类业务表,都会频繁用到这些规则
- 回顾重点:
AUTO_INCREMENT让 id 不用手填UNIQUE用来限制重复值DEFAULT用来减少重复传值- 先建表,再插入测试数据,最后观察查询结果
- 目录:
lessons/lesson40_query_update_delete_practice/ - 文件:
lessons/lesson40_query_update_delete_practice/README.mdlessons/lesson40_query_update_delete_practice/lesson40_query_update_delete_practice.sql
- 学习内容:
- 条件查询
UPDATEDELETE- 排序
- 查看修改结果
- 查看删除结果
- 当前重点:
- 这是一节把前面 SQL CRUD 真正串起来的实战课
- 目标是不只是会建表和插数据,还要真正学会怎么改数据、删数据、查结果
- 后面的 JDBC 本质上就是把这些 SQL 从 IDE 搬到 Java 代码里执行
- 回顾重点:
WHERE决定你操作哪几条数据UPDATE和DELETE一定要先想清楚条件- 先
SELECT看结果,再改,再查,最后再删 - 一节课里把查、改、删串起来,才算真正摸到 SQL 的节奏
- 目录:
lessons/lesson41_query_advanced_notes/ - 文件:
lessons/lesson41_query_advanced_notes/README.mdlessons/lesson41_query_advanced_notes/lesson41_query_advanced_notes.sql
- 学习内容:
AND/ORLIKEINBETWEENORDER BYLIMIT
- 当前重点:
- 这是一节把“简单查询”推进到“像真实列表接口查询”的课
- 目标是让你开始理解筛选、排序、分页这三件事在数据库里怎么表达
- 后面的 JDBC 查询列表、Spring Boot 列表接口,都会直接依赖这些 SQL 写法
- 回顾重点:
- 多条件查询的核心是
WHERE - 排序的核心是
ORDER BY - 分页最小模型先记
LIMIT offset, size - 从这一课开始,SQL 已经越来越接近真实后端接口查询
- 多条件查询的核心是
- 目录:
lessons/lesson42_jdbc_mysql_intro/ - 文件:
lessons/lesson42_jdbc_mysql_intro/README.mdlessons/lesson42_jdbc_mysql_intro/pom.xmllessons/lesson42_jdbc_mysql_intro/src/main/java/com/leon/lesson42/Lesson42JdbcMysqlIntro.javalessons/lesson42_jdbc_mysql_intro/src/main/resources/db.properties
- 学习内容:
- JDBC 是什么
ConnectionPreparedStatementResultSet- Java 连接 MySQL
- 用 Java 执行 SQL
- 当前重点:
- 这是一节从“手动写 SQL”进入“Java 发 SQL”的课
- 目标是让你第一次用 Java 代码真正连上 MySQL 并读到数据库结果
- 后面的 MyBatis、JPA、Spring Data,本质上都是对这层能力的进一步封装
- 回顾重点:
Java -> JDBC -> MySQLConnection负责连接数据库PreparedStatement负责带参数执行 SQLResultSet负责读取查询结果
- 目录:
lessons/lesson43_jdbc_crud_demo/ - 文件:
lessons/lesson43_jdbc_crud_demo/README.mdlessons/lesson43_jdbc_crud_demo/pom.xmllessons/lesson43_jdbc_crud_demo/src/main/java/com/leon/lesson43/Lesson43JdbcCrudDemo.javalessons/lesson43_jdbc_crud_demo/src/main/java/com/leon/lesson43/Lesson43User.javalessons/lesson43_jdbc_crud_demo/src/main/resources/db.properties
- 学习内容:
- JDBC 插入
- JDBC 查询列表
- JDBC 修改
- JDBC 删除
- 结果映射到 Java 对象
executeUpdate/executeQuery
- 当前重点:
- 这是一节把 JDBC 真正推进到 CRUD 的课
- 目标是不只会连库,还要会在 Java 里完成最小增删改查闭环
- 后面的 DAO、MyBatis、JPA,本质上都是在帮你更高效地做这些动作
- 回顾重点:
executeUpdate处理插入、修改、删除executeQuery处理查询- 查询结果可以映射成 Java 对象
- JDBC 代码的核心节奏还是:连接 -> 执行 -> 读取结果
- 目录:
lessons/lesson44_jdbc_transaction_demo/ - 文件:
lessons/lesson44_jdbc_transaction_demo/README.mdlessons/lesson44_jdbc_transaction_demo/pom.xmllessons/lesson44_jdbc_transaction_demo/src/main/java/com/leon/lesson44/Lesson44JdbcTransactionDemo.javalessons/lesson44_jdbc_transaction_demo/src/main/resources/db.properties
- 学习内容:
- 事务是什么
setAutoCommit(false)commitrollback- 转账场景
- 事务失败回滚
- 当前重点:
- 这是一节让你理解“多条 SQL 必须作为一个整体执行”的课
- 目标是让你知道为什么数据库不能只看单条 SQL 成功,还要看一组操作是否整体一致
- 后面的订单、支付、库存扣减这类场景,几乎都会依赖事务思维
- 回顾重点:
- 事务的核心是要么都成功,要么都失败
- 关闭自动提交后,必须自己决定
commit还是rollback - 出错时回滚,比“半成功半失败”安全得多
- 事务是 JDBC 进入真实业务开发的重要一步
- 目录:
lessons/lesson45_jdbc_layered_demo/ - 文件:
lessons/lesson45_jdbc_layered_demo/README.mdlessons/lesson45_jdbc_layered_demo/pom.xmllessons/lesson45_jdbc_layered_demo/src/main/java/com/leon/lesson45/Lesson45JdbcLayeredDemo.javalessons/lesson45_jdbc_layered_demo/src/main/java/com/leon/lesson45/Lesson45User.javalessons/lesson45_jdbc_layered_demo/src/main/java/com/leon/lesson45/Lesson45UserRepository.javalessons/lesson45_jdbc_layered_demo/src/main/java/com/leon/lesson45/Lesson45UserService.javalessons/lesson45_jdbc_layered_demo/src/main/java/com/leon/lesson45/Lesson45DbConfig.javalessons/lesson45_jdbc_layered_demo/src/main/resources/db.properties
- 学习内容:
- JDBC 分层思路
- Repository
- Service
- 实体对象
- 主程序协调流程
- 代码职责拆分
- 当前重点:
- 这是一节把 JDBC 代码从“全堆在 main 里”推进到“按职责拆分”的课
- 目标是让你开始理解为什么真实项目不会把所有数据库代码都写在一个类里
- 后面的 Spring Boot 分层,本质上就是把这种思路做得更规范
- 回顾重点:
- Repository 负责直接操作数据库
- Service 负责组织业务流程
- 实体对象负责承载数据
- 分层不是为了炫技,而是为了更容易维护
- 目录:
lessons/lesson46_jdbc_utils_refactor/ - 文件:
lessons/lesson46_jdbc_utils_refactor/README.mdlessons/lesson46_jdbc_utils_refactor/pom.xmllessons/lesson46_jdbc_utils_refactor/src/main/java/com/leon/lesson46/Lesson46JdbcUtilsRefactorDemo.javalessons/lesson46_jdbc_utils_refactor/src/main/java/com/leon/lesson46/Lesson46DbUtils.javalessons/lesson46_jdbc_utils_refactor/src/main/java/com/leon/lesson46/Lesson46User.javalessons/lesson46_jdbc_utils_refactor/src/main/java/com/leon/lesson46/Lesson46UserRepository.javalessons/lesson46_jdbc_utils_refactor/src/main/java/com/leon/lesson46/Lesson46UserService.javalessons/lesson46_jdbc_utils_refactor/src/main/resources/db.properties
- 学习内容:
- JDBC 工具类
- 配置与连接统一管理
- 减少重复代码
- Repository 继续简化
- Service 继续组织流程
- 工程化重构思路
- 当前重点:
- 这是一节把 JDBC 代码继续从“能跑”推进到“更像项目代码”的课
- 目标是让你看到哪些重复代码值得抽出来,哪些职责应该统一管理
- 后面的 Spring Boot 自动配置,本质上也是在进一步解决这类重复问题
- 回顾重点:
- 数据库配置和建连接逻辑可以抽到工具类
- Repository 不应该重复写加载配置的代码
- 抽工具类不是为了炫技,而是为了减少重复和降低出错率
- JDBC 学到这里,已经开始具备明显的工程化味道
- 目录:
lessons/lesson47_spring_boot_jdbc_intro/ - 文件:
lessons/lesson47_spring_boot_jdbc_intro/README.mdlessons/lesson47_spring_boot_jdbc_intro/pom.xmllessons/lesson47_spring_boot_jdbc_intro/src/main/java/com/leon/lesson47/Lesson47SpringBootJdbcIntroApplication.javalessons/lesson47_spring_boot_jdbc_intro/src/main/java/com/leon/lesson47/Lesson47User.javalessons/lesson47_spring_boot_jdbc_intro/src/main/java/com/leon/lesson47/Lesson47UserRepository.javalessons/lesson47_spring_boot_jdbc_intro/src/main/java/com/leon/lesson47/Lesson47UserService.javalessons/lesson47_spring_boot_jdbc_intro/src/main/java/com/leon/lesson47/Lesson47UserController.javalessons/lesson47_spring_boot_jdbc_intro/src/main/resources/application.properties
- 学习内容:
- Spring Boot 数据源自动配置
JdbcTemplate- Spring Boot 连接 MySQL
- Repository / Service / Controller 串联
- 启动时初始化表数据
- 最小数据库接口
- 当前重点:
- 这是一节把“手写 JDBC”正式过渡到“Spring Boot 数据访问”的课
- 目标是让你第一次看到 Spring Boot 怎么帮你接管连接、注入依赖、简化数据库操作
- 后面的 MyBatis、JPA、Spring Data,都会建立在这条工程化路线之上
- 回顾重点:
- Spring Boot 通过配置文件自动创建数据源
JdbcTemplate是对 JDBC 的一层更友好的封装- Controller / Service / Repository 这条链会继续复用
- 这一课的关键是理解“JDBC 没消失,只是被 Spring Boot 包装了”
- 目录:
lessons/lesson48_spring_boot_jdbc_crud/ - 文件:
lessons/lesson48_spring_boot_jdbc_crud/README.mdlessons/lesson48_spring_boot_jdbc_crud/pom.xmllessons/lesson48_spring_boot_jdbc_crud/src/main/java/com/leon/lesson48/Lesson48SpringBootJdbcCrudApplication.javalessons/lesson48_spring_boot_jdbc_crud/src/main/java/com/leon/lesson48/Lesson48User.javalessons/lesson48_spring_boot_jdbc_crud/src/main/java/com/leon/lesson48/Lesson48UserRequest.javalessons/lesson48_spring_boot_jdbc_crud/src/main/java/com/leon/lesson48/Lesson48UserRepository.javalessons/lesson48_spring_boot_jdbc_crud/src/main/java/com/leon/lesson48/Lesson48UserService.javalessons/lesson48_spring_boot_jdbc_crud/src/main/java/com/leon/lesson48/Lesson48UserController.javalessons/lesson48_spring_boot_jdbc_crud/src/main/resources/application.properties
- 学习内容:
- Spring Boot 查询接口
- Spring Boot 新增接口
- Spring Boot 修改接口
- Spring Boot 删除接口
@RequestBodyJdbcTemplateCRUD
- 当前重点:
- 这是一节把 Spring Boot 数据访问真正推进到接口级 CRUD 的课
- 目标是不只会查数据,还要会通过 HTTP 接口新增、修改、删除数据库数据
- 后面的统一返回、校验、异常处理,都会建立在这节课的接口能力上
- 回顾重点:
GET查数据POST新增数据PUT修改数据DELETE删除数据- Spring Boot 数据接口本质上仍然是 Controller / Service / Repository 配合
JdbcTemplate
- 目录:
lessons/lesson49_spring_boot_transaction_demo/ - 文件:
lessons/lesson49_spring_boot_transaction_demo/README.mdlessons/lesson49_spring_boot_transaction_demo/pom.xmllessons/lesson49_spring_boot_transaction_demo/src/main/java/com/leon/lesson49/Lesson49SpringBootTransactionApplication.javalessons/lesson49_spring_boot_transaction_demo/src/main/java/com/leon/lesson49/Lesson49Account.javalessons/lesson49_spring_boot_transaction_demo/src/main/java/com/leon/lesson49/Lesson49TransferRequest.javalessons/lesson49_spring_boot_transaction_demo/src/main/java/com/leon/lesson49/Lesson49AccountRepository.javalessons/lesson49_spring_boot_transaction_demo/src/main/java/com/leon/lesson49/Lesson49AccountService.javalessons/lesson49_spring_boot_transaction_demo/src/main/java/com/leon/lesson49/Lesson49AccountController.javalessons/lesson49_spring_boot_transaction_demo/src/main/resources/application.propertieslessons/lesson49_spring_boot_transaction_demo/lesson49_requests.http
- 学习内容:
@Transactional- Spring Boot 事务管理
- 转账场景
- 提交与回滚
- Service 层事务边界
- 当前重点:
- 这是一节把“数据库能改数据”推进到“多条 SQL 能整体正确执行”的课
- 目标是让你理解为什么真实项目里的业务动作经常必须放进事务里
- 你会第一次在 Spring Boot 接口里直观看到提交和回滚的区别
- 回顾重点:
- 事务解决的是一组 SQL 的一致性问题
- Spring Boot 里最常见的事务入口是 Service 方法上的
@Transactional - 成功时提交,抛异常时回滚
- 转账这类业务最适合用来理解事务为什么重要
- 目录:
lessons/lesson50_spring_boot_query_page_demo/ - 文件:
lessons/lesson50_spring_boot_query_page_demo/README.mdlessons/lesson50_spring_boot_query_page_demo/pom.xmllessons/lesson50_spring_boot_query_page_demo/src/main/java/com/leon/lesson50/Lesson50SpringBootQueryPageApplication.javalessons/lesson50_spring_boot_query_page_demo/src/main/java/com/leon/lesson50/Lesson50User.javalessons/lesson50_spring_boot_query_page_demo/src/main/java/com/leon/lesson50/Lesson50UserQuery.javalessons/lesson50_spring_boot_query_page_demo/src/main/java/com/leon/lesson50/Lesson50UserPageResponse.javalessons/lesson50_spring_boot_query_page_demo/src/main/java/com/leon/lesson50/Lesson50UserRepository.javalessons/lesson50_spring_boot_query_page_demo/src/main/java/com/leon/lesson50/Lesson50UserService.javalessons/lesson50_spring_boot_query_page_demo/src/main/java/com/leon/lesson50/Lesson50UserController.javalessons/lesson50_spring_boot_query_page_demo/src/main/resources/application.propertieslessons/lesson50_spring_boot_query_page_demo/lesson50_requests.http
- 学习内容:
- 查询参数接收
- 动态 SQL
- 条件筛选
- 分页查询
LIMIT/OFFSETtotal + list分页返回
- 当前重点:
- 这是一节把“查全部数据”推进到“更像真实后台列表页查询”的课
- 目标是让你真正把前端传参、Spring Boot 接参、SQL 条件拼装和分页返回串起来
- 这一课学完后,你会更清楚后台列表接口为什么总是带搜索、筛选和翻页
- 回顾重点:
- 列表接口最常见的能力就是条件查询和分页
page和size最终会换算成LIMIT/OFFSET- 分页接口通常不仅返回
list,还要返回total - 动态 SQL 的核心是“有参数才拼条件”
- 目录:
lessons/lesson51_mybatis_intro/ - 文件:
lessons/lesson51_mybatis_intro/README.mdlessons/lesson51_mybatis_intro/pom.xmllessons/lesson51_mybatis_intro/src/main/java/com/leon/lesson51/Lesson51MybatisIntroApplication.javalessons/lesson51_mybatis_intro/src/main/java/com/leon/lesson51/Lesson51User.javalessons/lesson51_mybatis_intro/src/main/java/com/leon/lesson51/Lesson51UserMapper.javalessons/lesson51_mybatis_intro/src/main/java/com/leon/lesson51/Lesson51UserService.javalessons/lesson51_mybatis_intro/src/main/java/com/leon/lesson51/Lesson51UserController.javalessons/lesson51_mybatis_intro/src/main/resources/application.propertieslessons/lesson51_mybatis_intro/src/main/resources/schema.sqllessons/lesson51_mybatis_intro/src/main/resources/data.sqllessons/lesson51_mybatis_intro/src/main/resources/mapper/Lesson51UserMapper.xmllessons/lesson51_mybatis_intro/lesson51_requests.http
- 学习内容:
- MyBatis 是什么
- Mapper 接口
- Mapper XML
- SQL 映射
- Spring Boot + MyBatis
- 当前重点:
- 这是一节把
JdbcTemplate继续推进到 MyBatis 的课 - 目标是让你第一次看懂 Mapper 接口和 XML 是怎么配合执行 SQL 的
- 这一课学完后,你会更清楚为什么很多 Java 项目会选择 MyBatis
- 这是一节把
- 回顾重点:
- MyBatis 仍然写 SQL,但把 SQL 和 Java 调用关系组织得更清楚
- Mapper 接口定义方法,Mapper XML 负责写 SQL
- Service 通常调用 Mapper,而不是直接操作数据库
- 这一课是后面学习动态 SQL 和 MyBatis CRUD 的起点
- 目录:
lessons/lesson52_mybatis_dynamic_sql/ - 文件:
lessons/lesson52_mybatis_dynamic_sql/README.mdlessons/lesson52_mybatis_dynamic_sql/pom.xmllessons/lesson52_mybatis_dynamic_sql/src/main/java/com/leon/lesson52/Lesson52MybatisDynamicSqlApplication.javalessons/lesson52_mybatis_dynamic_sql/src/main/java/com/leon/lesson52/Lesson52User.javalessons/lesson52_mybatis_dynamic_sql/src/main/java/com/leon/lesson52/Lesson52UserQuery.javalessons/lesson52_mybatis_dynamic_sql/src/main/java/com/leon/lesson52/Lesson52UserMapper.javalessons/lesson52_mybatis_dynamic_sql/src/main/java/com/leon/lesson52/Lesson52UserService.javalessons/lesson52_mybatis_dynamic_sql/src/main/java/com/leon/lesson52/Lesson52UserController.javalessons/lesson52_mybatis_dynamic_sql/src/main/resources/application.propertieslessons/lesson52_mybatis_dynamic_sql/src/main/resources/schema.sqllessons/lesson52_mybatis_dynamic_sql/src/main/resources/data.sqllessons/lesson52_mybatis_dynamic_sql/src/main/resources/mapper/Lesson52UserMapper.xmllessons/lesson52_mybatis_dynamic_sql/lesson52_requests.http
- 学习内容:
- 动态 SQL
<if><where>- 多条件查询
- MyBatis Query 对象
- 当前重点:
- 这是一节把 MyBatis 从固定查询推进到可组合条件查询的课
- 目标是让你理解为什么同一个 Mapper 方法可以支持多种筛选组合
- 这一课学完后,你会更清楚 MyBatis 在真实列表查询里的优势
- 回顾重点:
- 动态 SQL 解决的是查询条件不固定的问题
<if>控制某段条件是否出现<where>帮你自动处理WHERE和多余的AND- Query 对象很适合承接一组可选查询参数
- 目录:
lessons/lesson53_mybatis_crud/ - 文件:
lessons/lesson53_mybatis_crud/README.mdlessons/lesson53_mybatis_crud/pom.xmllessons/lesson53_mybatis_crud/src/main/java/com/leon/lesson53/Lesson53MybatisCrudApplication.javalessons/lesson53_mybatis_crud/src/main/java/com/leon/lesson53/Lesson53User.javalessons/lesson53_mybatis_crud/src/main/java/com/leon/lesson53/Lesson53UserMapper.javalessons/lesson53_mybatis_crud/src/main/java/com/leon/lesson53/Lesson53UserService.javalessons/lesson53_mybatis_crud/src/main/java/com/leon/lesson53/Lesson53UserController.javalessons/lesson53_mybatis_crud/src/main/resources/application.propertieslessons/lesson53_mybatis_crud/src/main/resources/schema.sqllessons/lesson53_mybatis_crud/src/main/resources/data.sqllessons/lesson53_mybatis_crud/src/main/resources/mapper/Lesson53UserMapper.xmllessons/lesson53_mybatis_crud/lesson53_requests.http
- 学习内容:
- MyBatis
insert - MyBatis
update - MyBatis
delete - 受影响行数
- 自增主键回填
- MyBatis
- 当前重点:
- 这是一节把 MyBatis 从“会查”推进到“会完整 CRUD”的课
- 目标是让你真正掌握新增、修改、删除在 Mapper XML 里怎么写
- 这一课学完后,你已经具备 MyBatis 基础业务开发能力
- 回顾重点:
useGeneratedKeys可以把新增后的 id 回填到对象里- 修改和删除通常要根据受影响行数判断是否成功
- Service 负责组织 CRUD 流程,Controller 负责接口输入输出
- 这一课是后面学习 MyBatis 分页和更复杂更新的基础
- 目录:
lessons/lesson54_mybatis_pagination/ - 文件:
lessons/lesson54_mybatis_pagination/README.mdlessons/lesson54_mybatis_pagination/pom.xmllessons/lesson54_mybatis_pagination/src/main/java/com/leon/lesson54/Lesson54MybatisPaginationApplication.javalessons/lesson54_mybatis_pagination/src/main/java/com/leon/lesson54/Lesson54User.javalessons/lesson54_mybatis_pagination/src/main/java/com/leon/lesson54/Lesson54UserQuery.javalessons/lesson54_mybatis_pagination/src/main/java/com/leon/lesson54/Lesson54UserPageResponse.javalessons/lesson54_mybatis_pagination/src/main/java/com/leon/lesson54/Lesson54UserMapper.javalessons/lesson54_mybatis_pagination/src/main/java/com/leon/lesson54/Lesson54UserService.javalessons/lesson54_mybatis_pagination/src/main/java/com/leon/lesson54/Lesson54UserController.javalessons/lesson54_mybatis_pagination/src/main/resources/application.propertieslessons/lesson54_mybatis_pagination/src/main/resources/schema.sqllessons/lesson54_mybatis_pagination/src/main/resources/data.sqllessons/lesson54_mybatis_pagination/src/main/resources/mapper/Lesson54UserMapper.xmllessons/lesson54_mybatis_pagination/lesson54_requests.http
- 学习内容:
- MyBatis 分页查询
count + pageListLIMIT / OFFSETpage / size / total / list- 列表分页返回结构
- 当前重点:
- 这是一节把 MyBatis 列表查询推进到真实分页接口的课
- 目标是让你理解为什么分页接口通常要分开查
total和当前页数据 - 这一课学完后,你会更清楚后台列表接口为什么总是带页码和总数
- 回顾重点:
- 分页接口通常至少有两次查询:总数和当前页列表
page和size最终会换算成LIMIT / OFFSET- 返回结构里常见字段是
page、size、total、list - Service 层通常负责页码归一化和 offset 计算
- 目录:
lessons/lesson55_mybatis_dynamic_update/ - 文件:
lessons/lesson55_mybatis_dynamic_update/README.mdlessons/lesson55_mybatis_dynamic_update/pom.xmllessons/lesson55_mybatis_dynamic_update/src/main/java/com/leon/lesson55/Lesson55MybatisDynamicUpdateApplication.javalessons/lesson55_mybatis_dynamic_update/src/main/java/com/leon/lesson55/Lesson55User.javalessons/lesson55_mybatis_dynamic_update/src/main/java/com/leon/lesson55/Lesson55UserUpdateRequest.javalessons/lesson55_mybatis_dynamic_update/src/main/java/com/leon/lesson55/Lesson55UserMapper.javalessons/lesson55_mybatis_dynamic_update/src/main/java/com/leon/lesson55/Lesson55UserService.javalessons/lesson55_mybatis_dynamic_update/src/main/java/com/leon/lesson55/Lesson55UserController.javalessons/lesson55_mybatis_dynamic_update/src/main/resources/application.propertieslessons/lesson55_mybatis_dynamic_update/src/main/resources/schema.sqllessons/lesson55_mybatis_dynamic_update/src/main/resources/data.sqllessons/lesson55_mybatis_dynamic_update/src/main/resources/mapper/Lesson55UserMapper.xmllessons/lesson55_mybatis_dynamic_update/lesson55_requests.http
- 学习内容:
- MyBatis 动态更新
<set>和<if>- 按需更新字段
PATCH接口- 更新请求对象
- 当前重点:
- 这是一节把 MyBatis 修改接口推进到真实编辑场景的课
- 目标是让你理解为什么真实项目里经常只更新部分字段,而不是整对象覆盖
- 这一课学完后,你会更清楚 MyBatis 为什么适合做灵活的后台编辑接口
- 回顾重点:
- 动态更新的重点是只改传入字段,没传的字段保持不动
- MyBatis 常用
<if>+<set>拼接动态UPDATE - 更新请求对象和实体对象最好分开,语义更清楚
- 空更新请求要尽早拦住,避免执行没有意义的 SQL
- 目录:
lessons/lesson56_mybatis_result_map/ - 文件:
lessons/lesson56_mybatis_result_map/README.mdlessons/lesson56_mybatis_result_map/pom.xmllessons/lesson56_mybatis_result_map/src/main/java/com/leon/lesson56/Lesson56MybatisResultMapApplication.javalessons/lesson56_mybatis_result_map/src/main/java/com/leon/lesson56/Lesson56UserProfile.javalessons/lesson56_mybatis_result_map/src/main/java/com/leon/lesson56/Lesson56UserMapper.javalessons/lesson56_mybatis_result_map/src/main/java/com/leon/lesson56/Lesson56UserService.javalessons/lesson56_mybatis_result_map/src/main/java/com/leon/lesson56/Lesson56UserController.javalessons/lesson56_mybatis_result_map/src/main/resources/application.propertieslessons/lesson56_mybatis_result_map/src/main/resources/schema.sqllessons/lesson56_mybatis_result_map/src/main/resources/data.sqllessons/lesson56_mybatis_result_map/src/main/resources/mapper/Lesson56UserMapper.xmllessons/lesson56_mybatis_result_map/lesson56_requests.http
- 学习内容:
- MyBatis
resultMap - 字段映射
- 下划线到驼峰
column和property- 映射规则复用
- MyBatis
- 当前重点:
- 这是一节把 MyBatis 查询结果映射推进到真实项目字段命名差异场景的课
- 目标是让你理解为什么数据库字段名和 Java 属性名不一致时,仍然可以稳定完成对象映射
- 这一课学完后,你会更清楚
resultMap在真实查询开发里的价值
- 回顾重点:
resultMap用来显式定义数据库列到 Java 属性的映射关系- 当字段名不一致时,
column和property的对应关系要写清楚 - 一个
resultMap可以被多个查询复用 - 这一课是后面学习多表查询和复杂对象组装的基础
- 目录:
lessons/lesson57_mybatis_multi_table_query/ - 文件:
lessons/lesson57_mybatis_multi_table_query/README.mdlessons/lesson57_mybatis_multi_table_query/pom.xmllessons/lesson57_mybatis_multi_table_query/src/main/java/com/leon/lesson57/Lesson57MybatisMultiTableQueryApplication.javalessons/lesson57_mybatis_multi_table_query/src/main/java/com/leon/lesson57/Lesson57UserDepartmentView.javalessons/lesson57_mybatis_multi_table_query/src/main/java/com/leon/lesson57/Lesson57UserMapper.javalessons/lesson57_mybatis_multi_table_query/src/main/java/com/leon/lesson57/Lesson57UserService.javalessons/lesson57_mybatis_multi_table_query/src/main/java/com/leon/lesson57/Lesson57UserController.javalessons/lesson57_mybatis_multi_table_query/src/main/resources/application.propertieslessons/lesson57_mybatis_multi_table_query/src/main/resources/schema.sqllessons/lesson57_mybatis_multi_table_query/src/main/resources/data.sqllessons/lesson57_mybatis_multi_table_query/src/main/resources/mapper/Lesson57UserMapper.xmllessons/lesson57_mybatis_multi_table_query/lesson57_requests.http
- 学习内容:
- MyBatis 多表查询
JOIN- 查询结果组装
- 联表字段别名
- 多表
resultMap
- 当前重点:
- 这是一节把 MyBatis 从单表查询推进到真实业务里常见联表查询的课
- 目标是让你理解为什么一个接口返回的数据,往往来自多张表
- 这一课学完后,你会更清楚联表查询和对象映射是怎么一起工作的
- 回顾重点:
JOIN用来按关联字段把多张表的数据查到一起- 多表查询结果通常仍然需要
resultMap做映射管理 - SQL 别名能帮助你把查询结果映射得更清楚
- 这一课是后面学习嵌套对象映射的基础
- 目录:
lessons/lesson58_mybatis_association/ - 文件:
lessons/lesson58_mybatis_association/README.mdlessons/lesson58_mybatis_association/pom.xmllessons/lesson58_mybatis_association/src/main/java/com/leon/lesson58/Lesson58MybatisAssociationApplication.javalessons/lesson58_mybatis_association/src/main/java/com/leon/lesson58/Lesson58Department.javalessons/lesson58_mybatis_association/src/main/java/com/leon/lesson58/Lesson58UserDetail.javalessons/lesson58_mybatis_association/src/main/java/com/leon/lesson58/Lesson58UserMapper.javalessons/lesson58_mybatis_association/src/main/java/com/leon/lesson58/Lesson58UserService.javalessons/lesson58_mybatis_association/src/main/java/com/leon/lesson58/Lesson58UserController.javalessons/lesson58_mybatis_association/src/main/resources/application.propertieslessons/lesson58_mybatis_association/src/main/resources/schema.sqllessons/lesson58_mybatis_association/src/main/resources/data.sqllessons/lesson58_mybatis_association/src/main/resources/mapper/Lesson58UserMapper.xmllessons/lesson58_mybatis_association/lesson58_requests.http
- 学习内容:
- MyBatis 嵌套对象映射
<association>- 联表结果分组
- 子对象映射
- 更合理的返回结构
- 当前重点:
- 这是一节把 MyBatis 从联表平铺返回推进到对象里套对象结构的课
- 目标是让你理解为什么真实项目里很多字段本来就应该属于子对象,而不是全部平铺在最外层
- 这一课学完后,你会更清楚 MyBatis 为什么适合做更贴近业务语义的对象映射
- 回顾重点:
<association>用来把查询结果中的一部分列映射到子对象- SQL 仍然是联表查询,但返回结构已经可以变成嵌套对象
- 子对象结构通常比平铺字段更符合真实业务语义
- 这一课是后面学习一对多查询的基础
- 目录:
lessons/lesson59_mybatis_collection/ - 文件:
lessons/lesson59_mybatis_collection/README.mdlessons/lesson59_mybatis_collection/pom.xmllessons/lesson59_mybatis_collection/src/main/java/com/leon/lesson59/Lesson59MybatisCollectionApplication.javalessons/lesson59_mybatis_collection/src/main/java/com/leon/lesson59/Lesson59DepartmentDetail.javalessons/lesson59_mybatis_collection/src/main/java/com/leon/lesson59/Lesson59UserItem.javalessons/lesson59_mybatis_collection/src/main/java/com/leon/lesson59/Lesson59DepartmentMapper.javalessons/lesson59_mybatis_collection/src/main/java/com/leon/lesson59/Lesson59DepartmentService.javalessons/lesson59_mybatis_collection/src/main/java/com/leon/lesson59/Lesson59DepartmentController.javalessons/lesson59_mybatis_collection/src/main/resources/application.propertieslessons/lesson59_mybatis_collection/src/main/resources/schema.sqllessons/lesson59_mybatis_collection/src/main/resources/data.sqllessons/lesson59_mybatis_collection/src/main/resources/mapper/Lesson59DepartmentMapper.xmllessons/lesson59_mybatis_collection/lesson59_requests.http
- 学习内容:
- MyBatis 一对多查询
<collection>- 列表结果组装
- 重复行归并
- 主对象和子列表
- 当前重点:
- 这是一节把 MyBatis 从单个子对象推进到子对象列表结构的课
- 目标是让你理解为什么联表 SQL 查出来会有重复主表行,但最终接口仍然可以返回一个对象加一个列表
- 这一课学完后,你会更清楚一对多查询在真实项目里是怎么落地的
- 回顾重点:
<collection>用来把多行子数据组装成列表属性- 外层和内层的
<id>都会影响结果归并 - SQL 的行数不等于最终 JSON 对象个数
- 这一课是后面学习分步查询的基础
- 目录:
lessons/lesson60_mybatis_step_query/ - 文件:
lessons/lesson60_mybatis_step_query/README.mdlessons/lesson60_mybatis_step_query/pom.xmllessons/lesson60_mybatis_step_query/src/main/java/com/leon/lesson60/Lesson60MybatisStepQueryApplication.javalessons/lesson60_mybatis_step_query/src/main/java/com/leon/lesson60/Lesson60DepartmentDetail.javalessons/lesson60_mybatis_step_query/src/main/java/com/leon/lesson60/Lesson60UserItem.javalessons/lesson60_mybatis_step_query/src/main/java/com/leon/lesson60/Lesson60DepartmentMapper.javalessons/lesson60_mybatis_step_query/src/main/java/com/leon/lesson60/Lesson60DepartmentService.javalessons/lesson60_mybatis_step_query/src/main/java/com/leon/lesson60/Lesson60DepartmentController.javalessons/lesson60_mybatis_step_query/src/main/resources/application.propertieslessons/lesson60_mybatis_step_query/src/main/resources/schema.sqllessons/lesson60_mybatis_step_query/src/main/resources/data.sqllessons/lesson60_mybatis_step_query/src/main/resources/mapper/Lesson60DepartmentMapper.xmllessons/lesson60_mybatis_step_query/lesson60_requests.http
- 学习内容:
- MyBatis 分步查询
- 主查询和子查询
select子查询- 主对象补子列表
- 查询策略差异
- 当前重点:
- 这是一节把 MyBatis 从联表归并推进到主查询加子查询分开执行的课
- 目标是让你理解为什么不联表,也可以把子列表补到主对象里
- 这一课学完后,你会更清楚查询策略不只有一种
- 回顾重点:
<collection>不只可以归并联表结果,也可以通过select触发子查询- 主查询和子查询拆开以后,SQL 职责会更清晰
- 分步查询和联表查询都能得到类似结果,但执行方式不同
- 这一课是后面理解 N+1 问题和查询取舍的基础
- 目录:
lessons/lesson61_mybatis_n_plus_one/ - 文件:
lessons/lesson61_mybatis_n_plus_one/README.mdlessons/lesson61_mybatis_n_plus_one/pom.xmllessons/lesson61_mybatis_n_plus_one/src/main/java/com/leon/lesson61/Lesson61MybatisNPlusOneApplication.javalessons/lesson61_mybatis_n_plus_one/src/main/java/com/leon/lesson61/Lesson61DepartmentDetail.javalessons/lesson61_mybatis_n_plus_one/src/main/java/com/leon/lesson61/Lesson61UserItem.javalessons/lesson61_mybatis_n_plus_one/src/main/java/com/leon/lesson61/Lesson61DepartmentMapper.javalessons/lesson61_mybatis_n_plus_one/src/main/java/com/leon/lesson61/Lesson61DepartmentService.javalessons/lesson61_mybatis_n_plus_one/src/main/java/com/leon/lesson61/Lesson61DepartmentController.javalessons/lesson61_mybatis_n_plus_one/src/main/resources/application.propertieslessons/lesson61_mybatis_n_plus_one/src/main/resources/schema.sqllessons/lesson61_mybatis_n_plus_one/src/main/resources/data.sqllessons/lesson61_mybatis_n_plus_one/src/main/resources/mapper/Lesson61DepartmentMapper.xmllessons/lesson61_mybatis_n_plus_one/lesson61_requests.http
- 学习内容:
- MyBatis 查询策略
- N+1 问题
- 联表查询 vs 分步查询
- SQL 次数观察
- 查询代价分析
- 当前重点:
- 这是一节把 MyBatis 从“会写查询”推进到“会分析查询代价”的课
- 目标是让你理解为什么两个接口返回结果一样,但执行 SQL 次数可能完全不同
- 这一课学完后,你会更清楚真实项目里为什么要关注查询策略
- 回顾重点:
- N+1 的核心是 1 次主查询加 N 次子查询,SQL 次数会随主数据条数增长
- 联表查询和分步查询没有绝对好坏,关键看场景和代价
- 控制台 SQL 日志是观察查询策略差异的直接手段
- 这一课是后面学习查询优化的基础
- 目录:
lessons/lesson62_mybatis_query_optimization/ - 文件:
lessons/lesson62_mybatis_query_optimization/README.mdlessons/lesson62_mybatis_query_optimization/pom.xmllessons/lesson62_mybatis_query_optimization/src/main/java/com/leon/lesson62/Lesson62MybatisQueryOptimizationApplication.javalessons/lesson62_mybatis_query_optimization/src/main/java/com/leon/lesson62/Lesson62UserDetail.javalessons/lesson62_mybatis_query_optimization/src/main/java/com/leon/lesson62/Lesson62UserSummary.javalessons/lesson62_mybatis_query_optimization/src/main/java/com/leon/lesson62/Lesson62SummaryQuery.javalessons/lesson62_mybatis_query_optimization/src/main/java/com/leon/lesson62/Lesson62UserMapper.javalessons/lesson62_mybatis_query_optimization/src/main/java/com/leon/lesson62/Lesson62UserService.javalessons/lesson62_mybatis_query_optimization/src/main/java/com/leon/lesson62/Lesson62UserController.javalessons/lesson62_mybatis_query_optimization/src/main/resources/application.propertieslessons/lesson62_mybatis_query_optimization/src/main/resources/schema.sqllessons/lesson62_mybatis_query_optimization/src/main/resources/data.sqllessons/lesson62_mybatis_query_optimization/src/main/resources/mapper/Lesson62UserMapper.xmllessons/lesson62_mybatis_query_optimization/lesson62_requests.http
- 学习内容:
- MyBatis 查询优化入门
- 控制返回字段
- 列表和详情拆分
- 条件筛选
limit
- 当前重点:
- 这是一节把 MyBatis 从“会比较查询次数”推进到“会减少不必要字段和结果量”的课
- 目标是让你理解为什么列表接口不应该默认把整行字段全部查出来
- 这一课学完后,你会更清楚轻量列表查询在真实项目里的价值
- 回顾重点:
- 查询优化的第一步通常是只查接口真正需要的字段
- 列表接口和详情接口最好分开设计
- 条件筛选和
limit往往也是很基础的优化动作 - 这一课是后面学习索引和
EXPLAIN的基础
- 目录:
lessons/lesson63_sql_index_explain/ - 文件:
lessons/lesson63_sql_index_explain/README.mdlessons/lesson63_sql_index_explain/schema.sqllessons/lesson63_sql_index_explain/data.sqllessons/lesson63_sql_index_explain/lesson63_explain_examples.sql
- 学习内容:
- SQL 索引
EXPLAIN- 单列索引
- 联合索引
- 执行计划观察
- 当前重点:
- 这是一节把数据库学习从“会写查询”推进到“会看查询为什么慢”的课
- 目标是让你理解索引是怎么帮助数据库更快定位数据,以及
EXPLAIN到底在看什么 - 这一课学完后,你会更清楚数据库性能分析最基础的入口在哪里
- 回顾重点:
- 索引是为了帮助数据库更快找到目标数据
EXPLAIN是观察 SQL 执行计划的入口- 初学阶段先重点看
key、rows、type - 这一课是后面学习索引失效和执行计划分析的基础
- 目录:
lessons/lesson64_index_invalid_cases/ - 文件:
lessons/lesson64_index_invalid_cases/README.mdlessons/lesson64_index_invalid_cases/schema.sqllessons/lesson64_index_invalid_cases/data.sqllessons/lesson64_index_invalid_cases/lesson64_index_invalid_examples.sql
- 学习内容:
- 索引失效常见场景
- 前缀通配符
- 函数处理
- 列计算
- 联合索引最左前缀
- 当前重点:
- 这是一节把数据库学习从“知道索引存在”推进到“知道为什么有索引却没用上”的课
- 目标是让你理解很多慢查询并不是没建索引,而是 SQL 写法让索引利用变差
- 这一课学完后,你会更清楚性能分析不能只看有没有索引
- 回顾重点:
LIKE '%xxx'、函数处理、列计算都可能让索引利用变差- 联合索引更强调最左前缀,不是随便写条件都一样
- 分析索引是否生效,要结合
EXPLAIN一起看 - 这一课是后面学习更系统查询优化案例的基础
- 目录:
lessons/lesson65_order_by_limit_covering_index/ - 文件:
lessons/lesson65_order_by_limit_covering_index/README.mdlessons/lesson65_order_by_limit_covering_index/schema.sqllessons/lesson65_order_by_limit_covering_index/data.sqllessons/lesson65_order_by_limit_covering_index/lesson65_order_limit_examples.sql
- 学习内容:
- 排序优化
- 分页查询
- 覆盖索引
ORDER BYLIMIT
- 当前重点:
- 这是一节把数据库优化从“索引有没有生效”推进到“真实列表页为什么会慢”的课
- 目标是让你理解排序、分页、返回字段设计和索引之间是怎么互相影响的
- 这一课学完后,你会更清楚为什么列表接口往往比普通条件查询更容易慢
- 回顾重点:
ORDER BY如果和索引顺序匹配,更容易高效执行- 覆盖索引的关键是查询需要的列已经都在索引里
LIMIT只是结果数量控制,不代表数据库前面的工作一定少- 这一课是后面学习深分页优化的基础
- 目录:
lessons/lesson66_deep_pagination_optimization/ - 文件:
lessons/lesson66_deep_pagination_optimization/README.mdlessons/lesson66_deep_pagination_optimization/schema.sqllessons/lesson66_deep_pagination_optimization/data.sqllessons/lesson66_deep_pagination_optimization/lesson66_deep_pagination_examples.sql
- 学习内容:
- 深分页
LIMIT offset, size- 游标分页
- 稳定排序
- 分页性能优化直觉
- 当前重点:
- 这是一节把分页学习从“会写分页 SQL”推进到“知道深页为什么会慢”的课
- 目标是让你理解结果条数不大时,数据库也可能因为跳过太多数据而变慢
- 这一课学完后,你会更清楚 offset 分页和游标分页分别适合什么场景
- 回顾重点:
- 深分页慢,核心不是返回行数大,而是前面跳过的数据越来越多
LIMIT offset, size更适合浅页或必须直接跳页的场景- 连续翻页场景更适合考虑游标分页
- 稳定排序时,最好用“排序字段 + 主键”一起做分页游标
- 目录:
lessons/lesson67_count_query_cost/ - 文件:
lessons/lesson67_count_query_cost/README.mdlessons/lesson67_count_query_cost/schema.sqllessons/lesson67_count_query_cost/data.sqllessons/lesson67_count_query_cost/lesson67_count_query_examples.sql
- 学习内容:
- 分页总数查询
count(*)count(1)count(id)- count 查询执行计划
- 当前重点:
- 这是一节把分页优化从“只看列表 SQL”推进到“开始单独分析总数 SQL”的课
- 目标是让你理解分页接口为什么经常会被第二条 count 查询拖慢
- 这一课学完后,你会更清楚 count 查询也要结合条件和索引来判断
- 回顾重点:
- 分页接口通常至少包含列表查询和总数查询两条 SQL
count(*)不是天然慢,关键还是看条件和索引count(*)、count(1)、count(id)在很多常见场景下执行计划会很接近- 分页性能分析要把列表 SQL 和 count SQL 分开看
- 目录:
lessons/lesson68_pagination_optimization_strategies/ - 文件:
lessons/lesson68_pagination_optimization_strategies/README.mdlessons/lesson68_pagination_optimization_strategies/schema.sqllessons/lesson68_pagination_optimization_strategies/data.sqllessons/lesson68_pagination_optimization_strategies/lesson68_pagination_strategy_examples.sql
- 学习内容:
- 经典分页
hasMore- 游标分页
- 受限总数
- 分页方案取舍
- 当前重点:
- 这是一节把分页优化从“优化单条 SQL”推进到“开始选择整体接口方案”的课
- 目标是让你理解分页接口为什么经常不是技术写法问题,而是业务需求组合问题
- 这一课学完后,你会更清楚什么时候该保留 total,什么时候该考虑
hasMore或 cursor
- 回顾重点:
- 分页优化不只是改 SQL,也包括减少不必要的需求
- 精确 total、任意跳页、深页也快,这几个目标经常不能同时低成本满足
- 后台表格和内容流,经常需要不同分页方案
- 先分清业务场景,再决定分页接口设计
- 目录:
lessons/lesson69_pagination_index_design/ - 文件:
lessons/lesson69_pagination_index_design/README.mdlessons/lesson69_pagination_index_design/schema.sqllessons/lesson69_pagination_index_design/data.sqllessons/lesson69_pagination_index_design/lesson69_pagination_index_examples.sql
- 学习内容:
- 联合索引顺序
- 复杂筛选分页
- 排序字段配合
- 高低频查询路径
- 索引设计取舍
- 当前重点:
- 这是一节把分页优化从“选择分页方案”推进到“开始针对复杂筛选列表设计索引”的课
- 目标是让你理解为什么同一个分页接口换个筛选条件,执行计划可能就明显不同
- 这一课学完后,你会更清楚联合索引顺序为什么要贴近高频查询路径
- 回顾重点:
- 复杂筛选列表的索引设计,本质是在平衡筛选、排序和分页
- 联合索引不追求包打天下,而是优先照顾高频查询路径
- 同一个接口支持的条件越多,索引设计取舍就越明显
- 看执行计划,才能验证联合索引顺序是否真的合理
- 目录:
lessons/lesson70_dynamic_sql_index_tradeoffs/ - 文件:
lessons/lesson70_dynamic_sql_index_tradeoffs/README.mdlessons/lesson70_dynamic_sql_index_tradeoffs/schema.sqllessons/lesson70_dynamic_sql_index_tradeoffs/data.sqllessons/lesson70_dynamic_sql_index_tradeoffs/lesson70_dynamic_sql_examples.sql
- 学习内容:
- 动态 SQL
- 可选条件组合
- 高低频查询路径
- 索引取舍
- 搜索接口复杂度
- 当前重点:
- 这是一节把分页索引设计从“复杂筛选”推进到“开始面对动态条件组合”的课
- 目标是让你理解为什么同一个搜索接口在不同入参下,实际上会变成很多种 SQL 路径
- 这一课学完后,你会更清楚为什么真实项目里很难靠一条万能索引覆盖所有动态查询
- 回顾重点:
- 动态 SQL 的本质是一个接口会生成很多种不同 SQL
- 不同 SQL 路径不可能永远共享同一条最佳索引
- 索引设计优先照顾高频动态查询路径
- 搜索功能越灵活,索引和执行计划取舍就越明显
- 目录:
lessons/lesson71_optional_sort_pagination/ - 文件:
lessons/lesson71_optional_sort_pagination/README.mdlessons/lesson71_optional_sort_pagination/schema.sqllessons/lesson71_optional_sort_pagination/data.sqllessons/lesson71_optional_sort_pagination/lesson71_optional_sort_examples.sql
- 学习内容:
- 可选排序
ORDER BY变化- 排序索引匹配
- 深分页影响
- 列表接口复杂度
- 当前重点:
- 这是一节把动态搜索列表继续推进到“排序字段也可变”的课
- 目标是让你理解为什么同一个分页接口排序一换,最优索引和执行计划也可能跟着换
- 这一课学完后,你会更清楚筛选、排序、分页必须一起分析
- 回顾重点:
WHERE条件一样,不代表不同ORDER BY性能一样- 排序字段顺序是联合索引设计的重要部分
- 可选排序会让同一个接口继续分裂成更多查询路径
- 高低频排序要区别对待,不能默认全部都同样完美
- 目录:
lessons/lesson72_table_api_tradeoffs/ - 文件:
lessons/lesson72_table_api_tradeoffs/README.mdlessons/lesson72_table_api_tradeoffs/schema.sqllessons/lesson72_table_api_tradeoffs/data.sqllessons/lesson72_table_api_tradeoffs/lesson72_table_api_examples.sql
- 学习内容:
- 接口能力取舍
- 高频路径优先
- 精确 total 与 hasMore
- 高低频排序
- 主列表接口收敛
- 当前重点:
- 这是一节把搜索列表优化继续推进到“接口能力分层”的课
- 目标是让你理解为什么真实后台表格不能把所有高成本能力都压在一个同步接口里
- 这一课学完后,你会更清楚默认列表、低频搜索、导出、统计为什么常常要分开设计
- 回顾重点:
- 列表接口优化,本质是在做高频路径优先级管理
- 不是所有能力都必须放进同一个主列表接口
- 高成本低频能力通常更适合拆分、降级或延后
- SQL 优化最后经常会回到接口设计和产品取舍
- 目录:
lessons/lesson73_table_capability_layering/ - 文件:
lessons/lesson73_table_capability_layering/README.mdlessons/lesson73_table_capability_layering/schema.sqllessons/lesson73_table_capability_layering/data.sqllessons/lesson73_table_capability_layering/lesson73_table_capability_examples.sql
- 学习内容:
- 能力分层
- 主列表接口
- 导出接口
- 统计接口
- 职责拆分
- 当前重点:
- 这是一节把后台表格优化继续推进到“同一页面不同能力要分开设计”的课
- 目标是让你理解为什么列表、导出、统计虽然查同一张表,但目标完全不同
- 这一课学完后,你会更清楚主列表接口为什么应该优先轻量和稳定
- 回顾重点:
- 列表、导出、统计虽然查同一份数据,但不是同一种能力
- 主列表接口优先轻量、分页、高频路径
- 导出能力通常更适合单独接口,甚至异步处理
- 统计能力更关注聚合口径,不该强行混进分页列表逻辑
- 目录:
lessons/lesson74_async_export_reasoning/ - 文件:
lessons/lesson74_async_export_reasoning/README.mdlessons/lesson74_async_export_reasoning/schema.sqllessons/lesson74_async_export_reasoning/data.sqllessons/lesson74_async_export_reasoning/lesson74_async_export_examples.sql
- 学习内容:
- 异步导出
- 大结果集查询
- 分批导出
- 同步与异步取舍
- 高结果集任务隔离
- 当前重点:
- 这是一节把后台表格能力分层继续推进到“导出任务为什么常常任务化”的课
- 目标是让你理解为什么大结果集查询不适合和页面列表共用同一条同步链路
- 这一课学完后,你会更清楚为什么异步导出和分批读取经常一起出现
- 回顾重点:
- 页面列表和导出任务虽然查同一份数据,但目标完全不同
- 结果集越大,同步导出越容易拖慢整条请求链路
- 异步导出本质是把“请求提交”和“慢任务处理”拆开
- 大结果集任务应该尽量和高频交互接口隔离
- 目录:
lessons/lesson75_large_result_batch_reading/ - 文件:
lessons/lesson75_large_result_batch_reading/README.mdlessons/lesson75_large_result_batch_reading/schema.sqllessons/lesson75_large_result_batch_reading/data.sqllessons/lesson75_large_result_batch_reading/lesson75_batch_read_examples.sql
- 学习内容:
- 大结果集读取
- offset 遍历
- 基于主键续查
- 分批处理
- 稳定续跑
- 当前重点:
- 这是一节把异步导出继续推进到“后台任务怎么稳稳把很多数据读出来”的课
- 目标是让你理解为什么大结果集任务通常更适合分批读取,而不是一次性全量读取或越来越深的 offset 遍历
- 这一课学完后,你会更清楚基于主键/游标推进为什么是批处理里的常见方案
- 回顾重点:
- 大结果集任务更关注稳定分批读完,而不是单次查最多
offset适合页面分页,不一定适合后台批量遍历- 基于主键或稳定游标续查,更适合长任务和失败续跑
- 批处理设计重点是稳定推进、可续跑、可控批次
- 目录:
lessons/lesson76_batch_vs_online_resource_isolation/ - 文件:
lessons/lesson76_batch_vs_online_resource_isolation/README.mdlessons/lesson76_batch_vs_online_resource_isolation/schema.sqllessons/lesson76_batch_vs_online_resource_isolation/data.sqllessons/lesson76_batch_vs_online_resource_isolation/lesson76_resource_isolation_examples.sql
- 学习内容:
- 在线接口
- 批处理任务
- 资源隔离
- 高低频流量分离
- 系统稳定性
- 当前重点:
- 这是一节把批处理读取继续推进到“为什么慢任务和在线请求不该共用同一套资源节奏”的课
- 目标是让你理解在线接口与批任务虽然都查数据库,但成功标准和资源诉求完全不同
- 这一课学完后,你会更清楚为什么系统设计里常说要隔离高频交互流量和低频重任务流量
- 回顾重点:
- 在线接口重视低延迟,批任务重视稳定推进
- 两类请求即使查同一张表,也不该默认共用同一套资源模型
- 资源隔离不仅是机器隔离,也包括并发、超时、连接池和链路隔离
- SQL 优化继续往后走,最终会进入系统资源治理问题
- 目录:
lessons/lesson77_background_job_system/ - 文件:
lessons/lesson77_background_job_system/README.mdlessons/lesson77_background_job_system/schema.sqllessons/lesson77_background_job_system/data.sqllessons/lesson77_background_job_system/lesson77_job_system_examples.sql
- 学习内容:
- 后台作业体系
- 任务状态
- 任务领取
- 失败重试
- 结果查询
- 当前重点:
- 这是一节把慢任务隔离继续推进到“后台作业体系基础设计”的课
- 目标是让你理解为什么慢任务不只是放后台跑一下,还需要任务状态、领取机制和失败重试
- 这一课学完后,你会更清楚为什么后台任务体系比一条异步 SQL 更像一个完整子系统
- 回顾重点:
- 慢任务更适合拆成“提交请求”和“后台执行”两个阶段
- 作业体系至少要有任务状态、领取机制、失败重试和结果查询
- worker 领取任务时,重点看的是状态和可执行时间
- 真正可用的慢任务体系,目标是长期稳定可运维
- 目录:
lessons/lesson78_job_idempotency/ - 文件:
lessons/lesson78_job_idempotency/README.mdlessons/lesson78_job_idempotency/schema.sqllessons/lesson78_job_idempotency/data.sqllessons/lesson78_job_idempotency/lesson78_job_idempotency_examples.sql
- 学习内容:
- 任务幂等性
- 稳定业务键
- 唯一约束防重
- 重试安全
- 业务副作用保护
- 当前重点:
- 这是一节把后台作业体系继续推进到“失败重试后如何避免重复副作用”的课
- 目标是让你理解为什么任务系统不仅要能重试,还要能安全重试
- 这一课学完后,你会更清楚数据库唯一约束和业务键为什么常常是任务幂等设计里的重要兜底手段
- 回顾重点:
- 任务重试天然会带来重复执行风险
- 真正要保护的是业务副作用不能重复生效
- 稳定业务键加唯一约束,是非常常见的幂等保护手段
- 可靠任务系统不是“能重试”就够了,还要“重试也安全”
- 目录:
lessons/lesson79_job_concurrent_claiming/ - 文件:
lessons/lesson79_job_concurrent_claiming/README.mdlessons/lesson79_job_concurrent_claiming/schema.sqllessons/lesson79_job_concurrent_claiming/data.sqllessons/lesson79_job_concurrent_claiming/lesson79_job_concurrent_claiming_examples.sql
- 学习内容:
- 并发领取
- 状态抢占
- 条件更新
- 影响行数判断
- worker 持有者校验
- 当前重点:
- 这是一节把后台作业体系继续推进到“多个 worker 同时抢任务时如何防止重复领取”的课
- 目标是让你理解为什么查到候选任务不等于真正领到任务
- 这一课学完后,你会更清楚任务领取为什么常常要依赖带条件更新和影响行数判断
- 回顾重点:
- 多个 worker 同时看到同一条待执行任务,是正常现象
- 真正关键的是谁先成功把任务状态从
PENDING抢占成RUNNING - 带条件更新和
ROW_COUNT()判断,是最常见的并发领取保护手段之一 - 任务系统不仅要防重复副作用,也要防重复领取
- 目录:
lessons/lesson80_job_timeout_reclaim/ - 文件:
lessons/lesson80_job_timeout_reclaim/README.mdlessons/lesson80_job_timeout_reclaim/schema.sqllessons/lesson80_job_timeout_reclaim/data.sqllessons/lesson80_job_timeout_reclaim/lesson80_job_timeout_reclaim_examples.sql
- 学习内容:
- 任务超时
- 心跳检查
- 卡死任务回收
- 重新调度
- 最大重试次数判断
- 当前重点:
- 这是一节把后台作业体系继续推进到“worker 失联后任务如何恢复”的课
- 目标是让你理解为什么
RUNNING状态也可能是假活跃,系统必须有超时回收能力 - 这一课学完后,你会更清楚心跳时间和条件回收为什么是任务恢复机制里的关键设计
- 回顾重点:
- 任务卡在
RUNNING是后台系统非常常见的问题 - 心跳超时检查,是识别卡死任务的常见手段之一
- 超时回收的本质,是把任务安全地放回可调度状态
- 一个可靠的任务系统,不只要能领取,还要能恢复
- 任务卡在
- 目录:
lessons/lesson81_retry_backoff_strategy/ - 文件:
lessons/lesson81_retry_backoff_strategy/README.mdlessons/lesson81_retry_backoff_strategy/schema.sqllessons/lesson81_retry_backoff_strategy/data.sqllessons/lesson81_retry_backoff_strategy/lesson81_retry_backoff_strategy_examples.sql
- 学习内容:
- 最大重试次数
- 固定间隔重试
- 指数退避
- 重试节奏控制
- 重试上限观察
- 当前重点:
- 这是一节把后台作业体系继续推进到“失败后应该以什么节奏再试”的课
- 目标是让你理解为什么自动重试不能无脑立刻重跑,而要控制间隔和次数
- 这一课学完后,你会更清楚固定间隔和指数退避为什么是两种常见的任务重试策略
- 回顾重点:
- 失败重试不是越快越好
max_retry_count是最基础的重试保护线- 固定间隔简单直接,指数退避更适合连续失败降压
- 一个可靠的任务系统,不只要能重试,还要会控制重试节奏
- 目录:
lessons/lesson82_dead_letter_and_compensation/ - 文件:
lessons/lesson82_dead_letter_and_compensation/README.mdlessons/lesson82_dead_letter_and_compensation/schema.sqllessons/lesson82_dead_letter_and_compensation/data.sqllessons/lesson82_dead_letter_and_compensation/lesson82_dead_letter_and_compensation_examples.sql
- 学习内容:
- 死信任务
- 人工补偿
- 失败收口
- 退出自动重试链路
- 失败任务后续处理
- 当前重点:
- 这是一节把后台作业体系继续推进到“失败任务最终怎么收口”的课
- 目标是让你理解为什么到达重试上限后,任务不能一直挂在自动重试链路里
- 这一课学完后,你会更清楚死信表和人工补偿单为什么是任务失败治理里的常见设计
- 回顾重点:
- 自动重试不是无限兜底能力
- 到达最大重试次数后,任务需要退出自动调度链路
- 死信任务是失败收口的重要手段之一
- 关键业务失败后,常常还需要人工补偿机制
- 目录:
lessons/lesson83_scheduler_and_worker_flow/ - 文件:
lessons/lesson83_scheduler_and_worker_flow/README.mdlessons/lesson83_scheduler_and_worker_flow/schema.sqllessons/lesson83_scheduler_and_worker_flow/data.sqllessons/lesson83_scheduler_and_worker_flow/lesson83_scheduler_and_worker_flow_examples.sql
- 学习内容:
- 调度器扫描
- 任务投递
- dispatch 记录
- worker 消费
- 执行链路回写
- 当前重点:
- 这是一节把后台作业体系继续推进到“任务是怎么真正跑起来”的课
- 目标是让你理解为什么任务表里的
PENDING数据不会自己执行,而必须经过调度器和 worker 配合 - 这一课学完后,你会更清楚
DISPATCHED、RUNNING、SUCCESS这些状态在执行链路里的区别
- 回顾重点:
- 任务表里的数据不会自己跑起来
- 调度器负责扫描到期任务并投递出去
- worker 负责真正执行任务并回写结果
- 一个真实任务系统,要把调度链路和执行链路分开理解
- 目录:
lessons/lesson84_job_execution_logs/ - 文件:
lessons/lesson84_job_execution_logs/README.mdlessons/lesson84_job_execution_logs/schema.sqllessons/lesson84_job_execution_logs/data.sqllessons/lesson84_job_execution_logs/lesson84_job_execution_logs_examples.sql
- 学习内容:
- 执行日志
- 任务时间线
- trace_id 串链路
- 错误日志查询
- 任务可观测性
- 当前重点:
- 这是一节把后台作业体系继续推进到“任务出了问题后怎么追踪和定位”的课
- 目标是让你理解为什么主任务表只能看当前状态,而不能完整还原一次任务执行过程
- 这一课学完后,你会更清楚日志表、trace_id 和结构化记录为什么是任务可观测性的关键基础
- 回顾重点:
- 主任务表不等于完整执行过程
- 执行日志和执行记录是排障的关键基础
trace_id能帮助你把一条任务链路串起来- 一个可靠的任务系统,不只要能执行,还要能观测
- 目录:
lessons/lesson85_alerts_and_manual_intervention/ - 文件:
lessons/lesson85_alerts_and_manual_intervention/README.mdlessons/lesson85_alerts_and_manual_intervention/schema.sqllessons/lesson85_alerts_and_manual_intervention/data.sqllessons/lesson85_alerts_and_manual_intervention/lesson85_alerts_and_manual_intervention_examples.sql
- 学习内容:
- 任务告警
- 失败通知
- 人工介入入口
- 告警状态流转
- 任务运维治理
- 当前重点:
- 这是一节把后台作业体系继续推进到“任务异常后怎么及时通知并交给人处理”的课
- 目标是让你理解为什么能查问题还不够,系统还必须能主动把关键问题暴露给人
- 这一课学完后,你会更清楚告警表、通知渠道和人工介入单为什么常常要配套设计
- 回顾重点:
- 可观测性不等于告警
- 告警让问题被及时发现,人工介入让问题真正进入处理链路
- 通知发出去,不等于问题已经解决
- 一个可靠的任务系统,不只要能观测,还要能触发处理
- 目录:
lessons/lesson86_scheduler_concurrency_guard/ - 文件:
lessons/lesson86_scheduler_concurrency_guard/README.mdlessons/lesson86_scheduler_concurrency_guard/schema.sqllessons/lesson86_scheduler_concurrency_guard/data.sqllessons/lesson86_scheduler_concurrency_guard/lesson86_scheduler_concurrency_guard_examples.sql
- 学习内容:
- 调度锁
- 条件更新抢占
- dispatch 唯一约束
- 重复投递防护
- 调度并发安全
- 当前重点:
- 这是一节把后台作业体系继续推进到“调度阶段怎么防止同一条任务被重复发出去”的课
- 目标是让你理解为什么并发风险不只存在于 worker 执行阶段,在 scheduler 扫描和投递阶段也必须有保护
- 这一课学完后,你会更清楚调度锁和 dispatch 唯一约束为什么常常要一起设计
- 回顾重点:
- 调度器阶段同样需要并发控制
- 条件更新可以防止多个调度器同时拿到同一条任务
- dispatch 唯一约束可以进一步兜底防重复投递
- 一个可靠的任务系统,不只要执行安全,还要调度安全
- 目录:
lessons/lesson87_task_system_review/ - 文件:
lessons/lesson87_task_system_review/README.mdlessons/lesson87_task_system_review/schema.sqllessons/lesson87_task_system_review/data.sqllessons/lesson87_task_system_review/lesson87_task_system_review_examples.sql
- 学习内容:
- 主任务表中心视角
- 调度与执行链路复盘
- 失败收口复盘
- 死信与人工介入联动
- 任务系统整体脑图
- 当前重点:
- 这是一节把任务系统这一整段知识点做整体收束的课
- 目标是让你把调度、执行、重试、死信、补偿、观测放进一条完整链路里理解
- 这一课学完后,你会更清楚排查任务问题时为什么要沿着链路查,而不是只盯单张表
- 回顾重点:
- 任务系统不是一张表,而是一组围绕
job_key协作的数据结构 - 调度、执行、重试、死信、补偿、观测需要放在一起理解
- 排查问题时,关键是按链路查,而不是只盯单张表
- 到这里,你应该开始从“会学单点”进入“会看系统整体”
- 任务系统不是一张表,而是一组围绕
- 目录:
lessons/lesson88_dto_vo_entity_layering/ - 文件:
lessons/lesson88_dto_vo_entity_layering/README.mdlessons/lesson88_dto_vo_entity_layering/pom.xmllessons/lesson88_dto_vo_entity_layering/src/main/java/...lessons/lesson88_dto_vo_entity_layering/src/main/resources/application.properties
- 学习内容:
- DTO 输入对象
- Entity 内部对象
- VO 输出对象
- 对象分层流转
- 接口工程化基础
- 当前重点:
- 这是一节从任务系统收束后切回接口工程化基础的课
- 目标是让你理解为什么真实接口代码不能把请求对象、数据库对象、返回对象混成一个类来用
- 这一课学完后,你会更清楚 DTO -> Entity -> VO 这条最基础的接口对象流转思路
- 回顾重点:
- DTO 管输入,Entity 管内部数据,VO 管输出展示
- 一个对象不要试图同时承担所有角色
- 对象分层能降低接口修改带来的连锁影响
- 接口工程化的第一步,就是把对象边界划清楚
- 目录:
lessons/lesson89_pagination_response_design/ - 文件:
lessons/lesson89_pagination_response_design/README.mdlessons/lesson89_pagination_response_design/pom.xmllessons/lesson89_pagination_response_design/src/main/java/...lessons/lesson89_pagination_response_design/src/main/resources/application.properties
- 学习内容:
- 统一分页返回结构
- 列表查询 DTO
- 列表项 VO 和详情 VO 区分
- PageResponse 设计
- 列表接口工程化收口
- 当前重点:
- 这是一节把接口工程化继续往前推进的课
- 目标是让你理解为什么真实项目里的列表接口通常不会每个都返回一套不同命名的数据结构
- 这一课学完后,你会更清楚分页接口为什么要统一外层结构,以及为什么列表和详情应该分开设计
- 回顾重点:
- 分页接口通常统一返回
pageNum、pageSize、total、list - 统一的是分页外层,不是所有业务字段都必须一样
- 列表项 VO 和详情 VO 通常应该分开
- 查询条件也应该通过 DTO 收口,而不是散落在 Controller 里
- 分页接口通常统一返回
- 目录:
lessons/lesson90_file_upload_download_basics/ - 文件:
lessons/lesson90_file_upload_download_basics/README.mdlessons/lesson90_file_upload_download_basics/pom.xmllessons/lesson90_file_upload_download_basics/src/main/java/...lessons/lesson90_file_upload_download_basics/src/main/resources/application.properties
- 学习内容:
- MultipartFile 基础
- 文件上传接口
- 文件下载接口
- 本地存储目录
- 文件接口和 JSON 接口差异
- 当前重点:
- 这是一节把接口开发继续往真实项目推进的课
- 目标是让你理解文件上传 / 下载为什么和普通 JSON 接口不一样,以及最基础的后端处理流程
- 这一课学完后,你会更清楚文件流、上传目录、下载响应头和文件元信息各自扮演什么角色
- 回顾重点:
- 上传文件最常见的接收对象是
MultipartFile - 上传请求通常使用
multipart/form-data - 下载接口通常需要设置
Content-Disposition - 文件内容保存和文件元信息记录是两件不同的事
- 上传文件最常见的接收对象是
- 目录:
lessons/lesson91_login_token_basics/ - 文件:
lessons/lesson91_login_token_basics/README.mdlessons/lesson91_login_token_basics/pom.xmllessons/lesson91_login_token_basics/src/main/java/...lessons/lesson91_login_token_basics/src/main/resources/application.properties
- 学习内容:
- 登录接口基础
- Token 返回与携带
- Bearer Token 请求头
- 拦截器校验登录态
- 退出登录基础流程
- 当前重点:
- 这是一节把接口开发进一步推进到“受保护接口”场景的课
- 目标是让你理解为什么很多接口不能匿名访问,以及登录、发 Token、拦截器校验之间是怎么串起来的
- 这一课学完后,你会更清楚
Authorization请求头、401、Bearer Token 和登录态校验之间的关系
- 回顾重点:
- 登录成功后,服务端通常会返回一个 Token 给前端
- 前端访问受保护接口时,通常要在
Authorization请求头里带上Bearer Token - 受保护接口常用拦截器统一做登录校验
- 这一课的实现是教学版认证流程,不是生产级完整方案
- 目录:
lessons/lesson92_api_testing_and_debugging/ - 文件:
lessons/lesson92_api_testing_and_debugging/README.mdlessons/lesson92_api_testing_and_debugging/pom.xmllessons/lesson92_api_testing_and_debugging/requests.httplessons/lesson92_api_testing_and_debugging/src/main/java/...lessons/lesson92_api_testing_and_debugging/src/main/resources/application.properties
- 学习内容:
- Apifox / Postman / IDE HTTP Client 对比
- 查询参数调试
- JSON 请求体调试
- Bearer Token 联调
- 基础排查顺序
- 当前重点:
- 这是一节把“会写接口”进一步推进到“会测接口、会联调接口”的课
- 目标是让你理解不同接口测试工具分别适合什么场景,并建立一套最基础的联调排查思路
- 这一课学完后,你会更清楚为什么请求地址、方法、请求头、状态码、返回体要一起看
- 回顾重点:
- 学习阶段很适合用 IDE HTTP Client 保存请求
- 团队联调场景很适合用 Apifox
- Token 调试时最容易漏的是
Authorization请求头 - 真正高效的联调,关键是固定排查顺序,而不是到处乱点
- 目录:
lessons/lesson93_spring_boot_testing_basics/ - 文件:
lessons/lesson93_spring_boot_testing_basics/README.mdlessons/lesson93_spring_boot_testing_basics/pom.xmllessons/lesson93_spring_boot_testing_basics/src/main/java/...lessons/lesson93_spring_boot_testing_basics/src/test/java/...lessons/lesson93_spring_boot_testing_basics/src/main/resources/application.properties
- 学习内容:
- 单元测试基础
- Controller 测试基础
MockMvc入门@SpringBootTest启动测试mvn test基本用法
- 当前重点:
- 这是一节把“会手工调接口”继续推进到“会做自动化验证”的课
- 目标是让你理解手工联调和自动化测试分别解决什么问题,以及最基础的测试通常怎么分层
- 这一课学完后,你会更清楚单元测试、Controller 测试、启动测试各自适合验证什么内容
- 回顾重点:
- 单元测试适合验证核心业务逻辑
- Controller 测试适合验证状态码、JSON 结构和异常返回
MockMvc是 Spring Boot 常见的接口测试方式mvn test是最基础的自动化测试执行命令
- 目录:
lessons/lesson94_packaging_profiles_and_deployment_basics/ - 文件:
lessons/lesson94_packaging_profiles_and_deployment_basics/README.mdlessons/lesson94_packaging_profiles_and_deployment_basics/pom.xmllessons/lesson94_packaging_profiles_and_deployment_basics/lesson94_run_examples.shlessons/lesson94_packaging_profiles_and_deployment_basics/src/main/java/...lessons/lesson94_packaging_profiles_and_deployment_basics/src/main/resources/...
- 学习内容:
mvn package基础java -jar运行方式- profile 配置切换
- 默认配置和环境配置覆盖关系
- 部署基础理解
- 当前重点:
- 这是一节把项目从“会开发”继续推进到“会交付、会运行”的课
- 目标是让你理解打包、独立运行、环境配置切换之间的关系,以及为什么后端项目不能只停留在 IDEA 里点启动
- 这一课学完后,你会更清楚 jar 是怎么来的、profile 是怎么切换的、部署的第一层到底在做什么
- 回顾重点:
mvn package负责打包,java -jar负责运行- profile 用来切换不同环境配置
- 默认配置和 profile 配置通常是覆盖关系
- 部署最基础的理解,就是把程序按目标环境跑起来
- 目录:
lessons/lesson95_mini_project_review/ - 文件:
lessons/lesson95_mini_project_review/README.mdlessons/lesson95_mini_project_review/pom.xmllessons/lesson95_mini_project_review/requests.httplessons/lesson95_mini_project_review/src/main/java/...lessons/lesson95_mini_project_review/src/test/java/...
- 学习内容:
- 认证链路复盘
- 分页列表和详情接口复盘
- DTO / Entity / VO 分层复盘
- Service 编排层职责
- 小项目结构收口
- 当前重点:
- 这是一节把前面零散知识点真正串成一个最小项目结构的课
- 目标是让你看到登录、分页、对象分层、联调、测试在一个项目里是怎么协作的
- 这一课学完后,你会更清楚为什么后端开发不能只盯单个接口,而要开始看整体结构
- 回顾重点:
- 小项目的关键不在功能多,而在结构开始完整
- Controller 负责接请求,Service 负责核心编排
- 列表接口和详情接口通常需要不同 VO
- 认证、分页、对象分层、测试应该开始放在一起理解
- 目录:
lessons/lesson96_phase1_final_review/ - 文件:
lessons/lesson96_phase1_final_review/README.mdlessons/lesson96_phase1_final_review/phase1_review_checklist.mdlessons/lesson96_phase1_final_review/phase2_learning_roadmap.md
- 学习内容:
- 第一阶段知识地图
- 模块化复习思路
- 第一阶段能力自测
- 常见卡点复盘
- 第二阶段学习路线图
- 当前重点:
- 这是一节把第一阶段真正收尾并收成体系的课
- 目标是让你从“学过很多零散课”过渡到“脑子里有一张完整地图”
- 这一课学完后,你会更清楚自己现在已经掌握了什么、哪里还薄弱、下一阶段应该先学什么
- 回顾重点:
- 第一阶段的关键成果,是完成 Java 后端入门闭环
- 现在最重要的是按模块复习,而不是机械逐课回看
- 你已经开始从“看单点”进入“看整体结构”
- 第二阶段最适合优先进入认证鉴权、缓存、ORM 进阶和项目实战
如果你后面想快速回顾,建议按下面顺序看:
-
第一轮:Java 基础重新热身
- 第 1~5 课
- 重点回顾:变量、方法、类、对象、
List、Map
-
第二轮:命令行项目基础重新过一遍
- 第 6~15 课
- 重点回顾:拆文件、
package/import、封装、输入处理、异常、小项目、文件读写
-
第三轮:Maven 和 Java 工程化重新建立感觉
- 第 16~17 课
- 重点回顾:
pom.xml、依赖、打包、target/
-
第四轮:Spring Boot 接口基础重新串起来
- 第 18~27 课
- 重点回顾:参数接收、请求体、JSON 返回、校验、分层、全局异常处理
-
第五轮:Spring Boot 配置体系重新串起来
- 第 28~33 课
- 重点回顾:
resources、@Value、Profiles、@ConfigurationProperties、YAML
-
第六轮:数据库与数据访问主线集中复习
- 第 34~62 课
- 重点回顾:
- 第 34~41 课:数据库、MySQL、SQL、建表和查询基础
- 第 42~46 课:JDBC CRUD、事务、分层、工具类
- 第 47~50 课:Spring Boot 数据访问
- 第 51~62 课:MyBatis、分页、动态 SQL、多表查询、映射、N+1、查询优化入门
-
第七轮:性能优化与任务系统集中复习
- 第 63~87 课
- 重点回顾:
- 第 63~72 课:索引、EXPLAIN、分页优化、动态 SQL 与索引取舍
- 第 73~76 课:后台表格接口、导出、大结果集、资源隔离
- 第 77~87 课:任务系统、调度、执行、重试、死信、补偿、观测、告警
-
第八轮:接口工程化收口
- 第 88~96 课
- 重点回顾:DTO / VO / Entity、统一分页、文件上传下载、登录 Token、联调、测试、打包运行、综合项目、阶段复盘
-
如果时间很少,优先只看这 6 节
- 第 18 课:最小 Spring Boot 项目结构
- 第 24 课:Controller / Service 分层
- 第 34 课:数据库在后端开发中的位置
- 第 51 课:MyBatis 入门
- 第 91 课:登录校验 / Token 基础
- 第 95 课:综合小项目设计与分层复盘
如果把第一阶段压缩成一句话,可以这样总结:
- 你已经完成了 Java 后端入门闭环
更具体一点说,你现在已经不只是会写几个零散 demo,而是已经接触并练过这些完整主线:
- Java 基础语法和面向对象
- Maven 和 Java 工程化基础
- Spring Boot 接口开发、配置体系、异常处理
- MySQL、SQL、JDBC、MyBatis、分页和查询优化
- 文件上传下载、登录 Token、接口联调、自动化测试
- 打包运行、配置切换、综合小项目结构
第一阶段结束时,最重要的成长不是“记住了多少语法”,而是:
- 你开始能把后端知识点连成系统来看
- 你开始能读懂一个最小后端项目是怎么组织的
- 你已经从“只会前端”进入“能继续做 Java 后端项目”的阶段
如果你后面想高效复习,最值得亲手再做一遍的是这 10 节:
- 第 2 课:方法、类、对象
- 第 7 课:
package和import - 第 16 课:Maven 项目结构
- 第 18 课:最小 Spring Boot 项目
- 第 24 课:Controller / Service 分层
- 第 34 课:数据库在后端开发中的位置
- 第 51 课:MyBatis 入门
- 第 63 课:索引与 EXPLAIN
- 第 91 课:登录校验 / Token 基础
- 第 95 课:综合小项目设计与分层复盘
这 10 节基本覆盖了:
- 语言基础
- 工程结构
- Web 接口
- 数据访问
- 性能意识
- 认证思路
- 项目整体结构
如果你准备继续,不建议再零散补知识,直接按这个顺序开第二阶段:
- Spring Security / JWT / 权限控制
- Redis 基础与登录态 / 缓存场景
- MyBatis-Plus 和数据库设计进阶
- 做一个更完整的小项目实战
你可以直接从这里开始:
- 第二阶段路线图:
lessons/lesson96_phase1_final_review/phase2_learning_roadmap.md - 第一阶段综合项目:
lessons/lesson95_mini_project_review/
第一阶段已经完成,建议下一步直接进入第二阶段,优先按这个顺序推进:
- Spring Security / JWT / 权限控制
- Redis 基础与登录态 / 缓存场景
- MyBatis-Plus 和数据库设计进阶
- 做一个更完整的小项目实战
如果你后面想继续,我建议直接从 Spring Security / JWT 开始。