知其然,知其所以然
Spring 全家桶 2026-10-19

TransactionTemplate 与编程式事务

实测 TransactionTemplate:回调抛 RuntimeException 或 setRollbackOnly() 都回滚;在同一个类里使用没有自调用问题;事务超时通过语句超时实现(setTimeout(1) 约 1025 ms 取消 select sleep(3));把 300 ms 的非数据库工作移出事务后,8 线程 2 连接的池从 1225 ms 降到 308 ms。

Spring 事务 TransactionTemplate 编程式事务 连接池 真实验证 动画演示
Spring 全家桶 2026-10-19

嵌套事务与 Savepoint

实测 NESTED 就是 JDBC Savepoint:MySQL 上依次出现 SAVEPOINT、(失败时 ROLLBACK TO SAVEPOINT)、RELEASE SAVEPOINT,整个过程只有一个 COMMIT;每次多出两条语句,耗时是 REQUIRED 的两倍多;JpaTransactionManager 默认不允许 NESTED,打开之后 Hibernate 的 JpaDialect 仍然不支持 savepoint。

Spring 事务 NESTED Savepoint 嵌套事务 真实验证 动画演示
Spring 全家桶 2026-10-19

多数据源事务:各自提交的风险与分布式事务的边界

实测多数据源下一个事务管理器只管一个数据源:@Transactional(txA) 写 A 和 B 后抛异常,A 回滚而 B 留下 1 行;嵌套模板先提交的一方撤销不了,后提交的失败会让两库不一致(七个场景里 4 个不一致);只有恰好是先提交的那一方失败时才碰巧一致。

Spring 事务 多数据源 分布式事务 最终一致 真实验证 动画演示
Spring 全家桶 2026-10-19

事务与 @Async、@TransactionalEventListener:提交之后再做事

实测 @TransactionalEventListener:普通 @EventListener 在事务里立刻执行,AFTER_COMMIT 在提交之后,回滚时收到 AFTER_ROLLBACK;@Transactional(REQUIRED) 的 AFTER_COMMIT 监听器在 Spring 7.0.9 启动时就被拒绝;@Async @EventListener 有 10% 读不到刚提交的订单(90/100),换成 AFTER_COMMIT 是 100/100;AFTER_COMMIT 监听器抛异常只记日志、不传给调用者。

Spring 事务 TransactionalEventListener AFTER_COMMIT 事务事件 真实验证 动画演示
Spring 全家桶 2026-10-19

DispatcherServlet:一个请求的完整路径

实测一个请求在 Spring MVC 里的完整路径:Filter → Interceptor.preHandle → 参数解析器 → Controller → ResponseBodyAdvice/消息转换器 → postHandle → afterCompletion → Filter;抛异常时没有 postHandle,由 @ExceptionHandler 处理;404 由静态资源处理器兜底再转 /error,405 不调用 preHandle;Boot 里有 6 个 HandlerMapping、4 个 HandlerAdapter、29 个参数解析器。

Spring MVC DispatcherServlet 请求处理 拦截器 真实验证 动画演示
Spring 全家桶 2026-10-19

HandlerMapping:请求怎么匹配到 Controller 方法,路径模式与优先级

实测 Spring MVC 的请求匹配:字面量优先于变量、精确优先于 /**;带正则的变量与普通变量同时匹配会在请求时报 Ambiguous(500),启动时发现不了;末尾斜杠、.json 后缀、大小写默认都不匹配(404);%2F 被 Tomcat 拒绝(400);produces / consumes / params / headers 可以区分同一路径的方法,不匹配时 406 / 415;** 在模式中间启动失败。

Spring MVC HandlerMapping 路径匹配 PathPattern 真实验证 动画演示
Spring 全家桶 2026-10-19

参数解析:HandlerMethodArgumentResolver 与 @RequestParam、@PathVariable、@RequestBody

实测 Spring MVC 的参数解析:必需参数缺失 400、类型转换失败 400、boolean 的 yes/on 当 true;不带注解的 int 参数缺失会抛 500 IllegalStateException;@RequestBody 的 JSON 错误、空 body 都是 400,多余字段被忽略;不带 setter 的 public 字段对象通过表单绑定一个字段都绑不上且不报错。

Spring MVC 参数解析 RequestParam RequestBody ModelAttribute 真实验证 动画演示
Spring 全家桶 2026-10-19

HttpMessageConverter 与 Jackson:日期、null、未知字段的坑

实测 Boot 4 的 Jackson 3 JSON 转换:日期类型写成 ISO 字符串,大整数写成数字(JS 会丢精度);反序列化时 LocalDateTime 带 Z 悄悄丢时区、Instant 的毫秒数被当成秒变成 +58768 年、Long 收到 1.5 悄悄变成 1,而 LocalDate 格式不对、enum 不认识会 400;Jackson 2 时代的 spring.jackson.serialization.write-dates-as-timestamps 在 Boot 4 里会启动失败。

Spring MVC Jackson HttpMessageConverter 日期 JSON 真实验证 动画演示
Spring 全家桶 2026-10-19

异常处理:@ExceptionHandler、@ControllerAdvice 与 ProblemDetail

实测 Spring MVC 异常处理:默认 /error JSON 只有 status、error、path;spring.mvc.problemdetails.enabled=true 只让标准 MVC 异常和 ResponseStatusException 输出 problem+json;@ControllerAdvice 里 @Order 小的先处理,控制器内的 @ExceptionHandler 优先于 Advice;Advice 里的 RuntimeException 兜底会吞掉带 @ResponseStatus 的异常(409 变成 500);Filter 里的异常不经过 Advice。

Spring MVC 异常处理 ControllerAdvice ProblemDetail 真实验证 动画演示
Spring 全家桶 2026-10-19

拦截器与 Servlet Filter:执行顺序与能看到什么

实测 Spring MVC 的拦截器与 Servlet Filter:Filter 包住整个拦截器链,preHandle 升序、postHandle 与 afterCompletion 倒序;preHandle 返回 false 后 Controller 与 postHandle 跳过,afterCompletion 只对返回过 true 的拦截器调用;404 请求 Filter 照常执行而拦截器只看路径匹配;Filter 读完请求体后 @RequestBody 得到 400。

Spring MVC 拦截器 Filter HandlerInterceptor 真实验证 动画演示
Spring 全家桶 2026-10-19

数据校验:@Valid、@Validated 与分组

实测 Spring MVC 的数据校验:@Valid 请求体失败抛 MethodArgumentNotValidException 且 Controller 不被调用,不写 @Valid 则脏数据直接进来;直接标在参数上的约束走内置的 HandlerMethodValidationException(400),控制器类上加 @Validated 反而变成 ConstraintViolationException(500);指定分组后默认组的约束不再检查;嵌套对象不写 @Valid 就不检查;Boot 默认响应和 problemdetails 都不带字段级违规。

Spring MVC 数据校验 Valid Validated 分组 真实验证 动画演示
Spring 全家桶 2026-10-19

内容协商与 Accept

实测 Spring MVC 内容协商:Accept 的 q 值和顺序决定 JSON 或 XML;返回 String 时只是按 Accept 贴 Content-Type 而不转换格式;produces 不匹配得到 406,ResponseEntity 显式指定 Content-Type 则不再协商;路径后缀(.json)在本版本下返回 404,?format= 要打开 favor-parameter 才生效,并且优先于 Accept;请求体方向 consumes 不满足得到 415。

Spring MVC 内容协商 Accept produces consumes 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号