系列:后端路线 · 收官篇
前面四篇 + 一个完整示例,你已经能写出来。但”写得出来”和”跑得通”之间,隔着一堆坑。本篇按”从外到内”的排查顺序,把最高频的问题与对应解法列给你。
1. 排查总原则:由外到内,逐层缩小
1 | 网络/防火墙 → 服务是否在跑 → 路由(404) → 参数(400) → 业务/数据库(500) → 数据正确与否 |
不要一上来就改代码。先确认”请求到底有没有到应用”,再往里查。
2. 连不上 / 超时(请求根本没反应)
| 现象 | 可能原因 | 排查/解决 |
|---|---|---|
Connection refused |
服务没启动 / 端口错 | ps -ef|grep java 看进程;确认 server.port |
| 云上访问不了 | 安全组未放行端口 | 云控制台放行 8080/对应端口 |
Could not connect to MySQL |
数据库地址/账号错、MySQL 未起、防火墙拦 3306 | 本地 mysql -u root -p 试连;检查 url 与 serverTimezone |
| 本地能连、服务器不能连 DB | 数据库只允许 localhost | 改 bind-address 或授权远程用户 |
排查顺序:先
ping/telnet ip port测网络连通,再查服务进程,再看日志。
3. 404 Not Found(路由没匹配)
@RequestMapping路径写错 / 少了前缀。- Controller 没被扫描到:启动类所在包的子包才被扫到(默认
@ComponentScan只扫启动类同包及子包)。解决:把 controller 放启动类包下,或显式@ComponentScan("com.xxx")。 - 用了
@Controller却期望返回 JSON(应是@RestController)。
4. 400 Bad Request(参数问题)
- 前端发 JSON,后端用
@RequestParam接 → 改用@RequestBody。 - 字段类型不匹配(字符串传数字、日期格式错)。
- 必填字段缺失。用
@Valid+@NotBlank等做校验,并全局异常处理返回清晰错误。
5. 500 Internal Error(服务端炸了)
第一步永远看日志 stack trace(tail -f app.log),定位异常类型与行号:
NullPointerException:对象未注入/未初始化(@Autowired 失败、字段没 set)。SQLException:SQL 语法错 / 字段名错 / 表不存在。DuplicateKeyException:唯一索引冲突(用户名重复,应业务层先查或捕获)。Transaction rolled back:事务内抛异常被回滚,看根因异常。
绝不要”盲改代码”。异常信息 + 行号基本能直接定位。
6. 中文乱码
- 数据库 / 表 / 连接都要
utf8mb4:建表CHARSET=utf8mb4,连接串characterEncoding=utf8mb4。 - 响应乱码:
produces = "application/json;charset=utf-8"或全局配置spring.http.encoding.charset=utf-8。 - 文件/IDE 编码统一 UTF-8。
7. 事务不生效(@Transactional 没回滚)
| 原因 | 说明 |
|---|---|
| 同类方法互相调用 | this.methodB() 不走代理,事务失效;需注入自己或拆到另一类 |
| 异常被 catch 吞掉 | 抛出的异常没往外冒,事务感知不到 → 必须 rethrow 或 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() |
| 抛的是受检异常/自定义异常 | 默认只回滚 RuntimeException;用 @Transactional(rollbackFor = Exception.class) |
| 方法非 public | Spring 事务基于代理,private/protected 不生效 |
| 数据库引擎非 InnoDB | MyISAM 不支持事务 |
8. 慢查询 / 接口响应慢
- 没加索引:用
EXPLAIN看是否type=ALL(全表扫);按查询条件建索引(复习 Part 1)。 - N+1 查询:循环里查库(for 里
getById)→ 改成批量IN或联表。 - 返回数据过大:分页
LIMIT没用,一次查全表。 - 连接池打满:并发高时
HikariCP连接不够,调大maximum-pool-size。
9. 跨域 CORS 报错(浏览器红字)
Access-Control-Allow-Origin 缺失 → 后端加 CORS 配置(见 Part 4)。注意:预检 OPTIONS 也要放行;allowCredentials=true 时 allowedOriginPatterns 不能用 *,须指定具体域名。
10. 调试工具箱(必备)
| 工具 | 用途 |
|---|---|
curl |
命令行发请求,排除前端干扰,验证接口本身 |
| Postman / Apifox | 图形化调试、保存集合、环境变量 |
tail -f app.log |
实时看应用日志 |
| IDEA 断点调试 | 逐行看变量值,定位逻辑错 |
EXPLAIN <sql> |
分析 SQL 是否走索引 |
| Spring Boot Actuator | /actuator/health、/metrics 看应用健康与指标 |
telnet ip port / ping |
测网络连通 |
11. 调试心法(三条)
- 先复现,再改:不能稳定复现的 bug 不要急着改,先拿到稳定复现步骤。
- 缩小范围:注释掉一半逻辑、用最小请求复现,二分定位。
- 看证据,不猜:异常栈、HTTP 状态码、数据库实际数据,比”我觉得应该是…”可靠。
12. 自测 Checklist(上线前过一遍)
- 接口用 curl/Postman 实测通过(不只靠前端)
- 异常输入(空值、超长、错误类型)有合理响应,不 500
- 关键查询已加索引,慢 SQL 已排查
- 敏感配置(密码)走环境变量,未硬编码
- 生产配置(profile=prod)生效,日志路径正确
- 服务进程在后台常驻,重启可恢复
- 跨域(如需)已正确配置
系列到此收官。你已走完:全链路概览 → MySQL → Spring Boot → API/HTTP → 部署 → 完整示例 → 调试。
下一步可深入:Redis 缓存、RabbitMQ 消息队列、Spring Security/JWT 鉴权、MySQL 锁与执行计划、分库分表与读写分离、Docker/K8s 部署。每一块都可以在此基础上单独成篇。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 dmw's blog!
评论



