排查Hibernate 6中“无法确定推荐JdbcType”异常的原因
Hibernate 6中@Embeddable类@Transient反向引用引发JdbcTypeRecommendationException的解决办法
问题现象
将Spring Boot从2.7.x(对应Hibernate 5)升级到3.2.3(对应Hibernate 6)后,包含以下代码的应用抛出JdbcTypeRecommendationException异常:
Could not determine recommended JdbcType for Java type...
@Entity(name = "JobGroup") public class JobGroupEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; @ElementCollection private List<JobReference> jobs = new ArrayList<>(); } @Embeddable public class JobReference { private String jobId; @Transient private JobGroupEntity jobGroup; }
移除JobReference中的jobGroup字段后异常消失,即使移除@Transient注解或添加@JdbcTypeCode注解也无法解决问题。
原因分析
Hibernate 5的处理逻辑
在Hibernate 5中,@Embeddable类中标注@Transient的字段会被完全忽略,不会参与任何映射元数据的收集和类型解析流程,因此这类实体类型的反向引用不会触发任何映射相关的校验。
Hibernate 6的变更
Hibernate 6对元数据收集和类型校验机制做了大幅调整:
- 注解兼容性:Spring Boot 3基于Jakarta EE API,Hibernate 6仅识别
jakarta.persistence.Transient注解,若仍使用旧的javax.persistence.Transient,注解会失效,Hibernate会将该字段视为需要映射的字段。 - 元数据校验增强:即使使用了正确的
@Transient注解,当字段类型为实体类时,Hibernate的类型解析器仍会尝试解析该类型的JDBC映射规则,尤其在@ElementCollection关联场景下,这种校验会触发异常。
解决方案
1. 替换为Jakarta版本的@Transient注解
确保JobReference中的@Transient来自jakarta.persistence包,而非旧的javax.persistence:
import jakarta.persistence.Transient; @Embeddable public class JobReference { private String jobId; @Transient private JobGroupEntity jobGroup; }
2. 结合@Access注解明确访问方式
如果替换注解后仍有问题,可通过@Access强制Hibernate通过属性访问而非字段访问,从而忽略该字段的映射:
import jakarta.persistence.Access; import jakarta.persistence.AccessType; import jakarta.persistence.Transient; @Embeddable public class JobReference { private String jobId; @Transient @Access(AccessType.PROPERTY) private JobGroupEntity jobGroup; // 必须添加getter和setter public JobGroupEntity getJobGroup() { return jobGroup; } public void setJobGroup(JobGroupEntity jobGroup) { this.jobGroup = jobGroup; } }
3. 字段初始化方式调整(可选)
如果仅需在内存中维护反向引用,可直接在构造方法或业务逻辑中初始化该字段,避免Hibernate的元数据解析触发异常:
@Embeddable public class JobReference { private String jobId; private JobGroupEntity jobGroup; // 构造方法中初始化,或通过业务方法设置,不依赖Hibernate映射 public JobReference() { this.jobGroup = null; } // 仅提供业务层面的getter/setter,不添加任何JPA注解 public JobGroupEntity getJobGroup() { return jobGroup; } public void setJobGroup(JobGroupEntity jobGroup) { this.jobGroup = jobGroup; } }
内容的提问来源于stack exchange,提问作者E-Riz
相关产品推荐
相关产品推荐

