Spring Boot 2迁3启动报错:@MapsId指定字段不存在的解决方案咨询
Spring Boot 2迁移至Spring Boot 3后@MapsId映射错误解决方案
问题原因
错误核心是Hibernate 6(Spring Boot 3默认依赖版本)对@MapsId的字段匹配规则更严格:你的嵌入ID类CorporateAccountLinkageKey中属性使用驼峰命名(如corporateAccountId),但@MapsId注解里写的是数据库列名的下划线格式(如corporate_account_id),Hibernate 6无法自动将下划线名称映射到驼峰属性,导致找不到对应字段。
解决方案
不需要替换@MapsId注解,只需让@MapsId指定的名称与嵌入ID类中的属性名一致即可,无需修改嵌入ID类本身。
修改后的实体类代码
import jakarta.persistence.EmbeddedId; import jakarta.persistence.Entity; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.MapsId; import jakarta.persistence.Table; @Entity @Table(name = "corporate_account_linkages") public class CorporateAccountLinkage { @EmbeddedId private CorporateAccountLinkageKey corporateAccountLinkageKey; @ManyToOne @MapsId("corporateAccountId") // 改为嵌入ID类中的驼峰属性名 @JoinColumn(name = "corporate_account_id") // 数据库列名保留下划线格式不变 private CorporateAccount corporateAccount; // 建议修正变量名,避免与ID属性混淆 @ManyToOne @MapsId("linkedCorporateAccountId") // 改为嵌入ID类中的驼峰属性名 @JoinColumn(name = "linked_corporate_account_id") // 数据库列名保留下划线格式不变 private CorporateAccount linkedCorporateAccount; // 建议修正变量名,避免与ID属性混淆 // 补充getter、setter方法 }
嵌入ID类(仅补充规范要求内容)
import jakarta.persistence.Column; import jakarta.persistence.Embeddable; import java.io.Serializable; import java.util.Objects; @Embeddable public class CorporateAccountLinkageKey implements Serializable { @Column(name = "corporate_account_id", nullable = false) private Long corporateAccountId; @Column(name = "linked_corporate_account_id", nullable = false) private Long linkedCorporateAccountId; // JPA规范强制要求:无参构造方法 public CorporateAccountLinkageKey() {} // 全参构造方法 public CorporateAccountLinkageKey(Long corporateAccountId, Long linkedCorporateAccountId) { this.corporateAccountId = corporateAccountId; this.linkedCorporateAccountId = linkedCorporateAccountId; } // JPA规范强制要求:equals和hashCode方法 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CorporateAccountLinkageKey that = (CorporateAccountLinkageKey) o; return Objects.equals(corporateAccountId, that.corporateAccountId) && Objects.equals(linkedCorporateAccountId, that.linkedCorporateAccountId); } @Override public int hashCode() { return Objects.hash(corporateAccountId, linkedCorporateAccountId); } // 补充getter、setter方法 public Long getCorporateAccountId() { return corporateAccountId; } public void setCorporateAccountId(Long corporateAccountId) { this.corporateAccountId = corporateAccountId; } public Long getLinkedCorporateAccountId() { return linkedCorporateAccountId; } public void setLinkedCorporateAccountId(Long linkedCorporateAccountId) { this.linkedCorporateAccountId = linkedCorporateAccountId; } }
额外说明
@MapsId的参数必须是嵌入ID类中的属性名称,而非数据库列名,这是Hibernate 6严格遵循JPA规范的表现,Spring Boot 2依赖的Hibernate 5对该规则校验更宽松,允许混用列名与属性名。- 嵌入ID类必须实现
Serializable接口,同时提供无参构造、equals和hashCode方法,这是JPA的强制要求,Hibernate 6会严格校验这些规范。
内容的提问来源于stack exchange,提问作者Peter Penzov
相关产品推荐
相关产品推荐

