You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 1.5.21中Hibernate Validation在Tomcat与Jetty的表现差异

问题分析与解决方案

首先得明确:这个问题和Tomcat/Jetty容器本身没有直接关系,核心是Hibernate Validator的校验触发逻辑在不同环境下的差异,刚好切换容器时暴露了这个问题。

为什么Tomcat下没报错,Jetty下却触发了?

你提到@NotEmpty注解已经用了两年,只在Web层校验@RequestBody参数,Tomcat下保存telephone=null的实体没问题,但Jetty下保存就触发ConstraintViolation——本质是Hibernate在实体持久化时的校验开关被打开了。

在Spring Boot 1.5.x中,Hibernate的Bean Validation触发由配置spring.jpa.properties.javax.persistence.validation.mode控制:

  • 默认值AUTO:Hibernate会自动检测是否启用校验,但这个逻辑可能因为依赖版本、配置文件加载顺序等因素出现差异
  • NONE:完全关闭JPA层面的实体校验
  • CALLBACK:在pre-persist/pre-update等实体生命周期回调时触发校验

你之前Tomcat环境中,这个配置大概率是被隐式设置为NONE,或者AUTO模式下Hibernate没有启用持久化校验;而切换到Jetty后,配置被重置,校验模式变成了CALLBACK,所以userRepository.save()时触发了@NotEmpty的校验。

另外要纠正一个认知:org.hibernate.validator.constraints.NotEmpty的规则是校验对象不为null且长度/大小大于0,所以你给telephone设为null时,确实违反了这个约束——Jetty下的报错是符合校验规则的,之前Tomcat下的“正常”其实是因为校验没被触发。

两种解决思路,按需选择

1. 关闭JPA层面的实体校验(快速匹配旧行为)

如果只想保持和Tomcat下一样的逻辑,不在持久化时触发Bean Validation,直接在application.properties里加配置:

spring.jpa.properties.javax.persistence.validation.mode=NONE

这样Hibernate在保存/更新实体时就不会触发任何校验,和你之前的运行逻辑完全一致。

2. 替换注解(更规范的长期方案)

既然你的需求是禁止空字符串,但允许null(数据库字段也允许null),那@NotEmpty其实不是合适的注解——应该用javax.validation.constraints.NotBlank。

@NotBlank的规则是:字符串不为null,且去除首尾空白后长度大于0,刚好符合你“禁止空字符串,允许null”的需求。修改实体字段:

@Column(name = "telephone")
@NotBlank(message = "*Please provide a telephone number")
private String telephone;

这样不管是Web层的@Valid校验,还是JPA持久化时的校验,逻辑都和你的需求匹配,不会再出现null触发报错的问题。

额外提醒

数据库字段的null约束和Bean Validation是两层独立的逻辑:

  • 数据库的null约束是存储层面的规则
  • Bean Validation是应用层的校验规则
    之前Tomcat下的“正常”其实是应用层校验没被触发,并非逻辑正确,Jetty下的报错反而帮你发现了注解使用的小问题。

内容的提问来源于stack exchange,提问作者sebasira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 16:53:13