@Validated写在Mapper接口上无效,因为MyBatis的Mapper是JDK动态代理生成、非Spring托管Bean,Spring校验切面不扫描它;校验必须置于@Controller或@Service层入参,由Spring AOP拦截执行,且需配套全局异常处理器捕获MethodArgumentNotValidException或ConstraintViolationException。

MyBatis 本身不校验参数,必须靠上层(Spring + javax.validation)拦截并提前拒绝非法入参,否则 SQL 执行前根本不会触发校验逻辑。
为什么 @Validated 写在 Mapper 接口上没用
MyBatis 的 Mapper 接口是 JDK 动态代理生成的,Spring 的 @Validated 注解只对 Spring 管理的 Bean(如 @Service、@Controller)生效。直接在 Mapper 方法上加 @Validated 或 @Valid,Spring 校验器压根不扫描、不执行。
- MyBatis 不解析 JSR-303 注解,也不调用
Validator实例 -
Mapper接口方法调用走的是 MyBatis 的SqlSession路径,绕过了 Spring AOP 的校验切面 - 实测:加了注解但传
null或空字符串,照样进 SQL,报错也是数据库层面(如NULL not allowed)
正确位置:@Validated 必须放在 Service 或 Controller 层入参
校验动作要发生在 MyBatis 执行之前,且必须由 Spring 容器托管的组件承载。最常用、最稳妥的位置是 @Service 方法或 @PostMapping 入参。
- 在
@Service方法参数上加@Valid,并在实体类字段标注@NotBlank、@Min(1)等 - 搭配
@Validated可启用分组校验(如CreateGroup.class/UpdateGroup.class) - Controller 层加
@Valid更早拦截,适合快速失败;Service 层加更利于复用和单元测试 - 示例:
@Service public class UserService { public void saveUser(@Valid @RequestBody User user) { // ← 此处校验生效 userMapper.insert(user); // ← 此处才进 MyBatis } }
MyBatis 自己能做的“校验”只有类型和绑定层面
MyBatis 原生只做两件事:参数类型匹配、SQL 占位符绑定。它会检查 #{xxx} 中的 xxx 是否能在参数对象中 get 到,但不会管值是否为空、长度是否超限、格式是否合法。
-
@Param("name")是为多参数提供命名,防止位置错乱,不是校验手段 -
resultMap中的notNullColumns是结果集校验(查完后判断列是否为空),不作用于入参 - TypeHandler 转换时可能抛
ClassCastException,但这属于类型错误,不是业务校验 - 真要拦截非法参数,唯一可靠路径就是 Spring 的
MethodValidationPostProcessor+LocalValidatorFactoryBean
最容易被忽略的一点:校验失败默认抛 MethodArgumentNotValidException(Controller 层)或 ConstraintViolationException(Service 层),必须配全局异常处理器,否则前端收到 500 而不是 400 + 错误字段信息。

















