You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Hibernate Schema校验报错:列类型不匹配问题求助

Hibernate Schema校验列类型不匹配问题的排查与解决

我来帮你拆解这个问题——你遇到的错误看起来是列类型不匹配,但根源其实是复合主键的映射方式错误,下面一步步给你分析和解决:

问题回顾

你在使用Hibernate做Schema校验时收到如下错误:

Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: wrong column type encountered in column [traject_id] in table [tt_traject_ref_toets]; found [int (Types#INTEGER)], but expecting [tinyblob (Types#VARBINARY)]

你已经尝试给Trajectid字段添加columnDefinition="int(10)",但问题依然存在。

核心原因分析

看你的ToetsBijTraject实体类,你直接把关联的TrajectToets对象标记为@Id

@Id
@Column(name = "traject_id")
private Traject traject;
@Id
@Column(name = "toets_id")
private Toets toets;

Hibernate默认会把实体对象当作序列化的二进制数据来处理,所以它期望数据库列是tinyblob类型,而不是你数据库里的int(10) unsigned——这就是类型不匹配的根源,和Traject类的配置无关。

解决方案

这里有两种标准的复合主键映射方式,推荐第一种:

方案1:使用@EmbeddedId(推荐)

这种方式更符合JPA规范,结构也更清晰:

  1. 首先创建一个嵌入式主键类,必须实现Serializable
@Embeddable
public class ToetsBijTrajectId implements Serializable {
    @Column(name = "traject_id", columnDefinition = "int(10) unsigned")
    private Integer trajectId;
    
    @Column(name = "toets_id", columnDefinition = "int(10) unsigned")
    private Integer toetsId;
    
    // 必须重写equals和hashCode方法,用于主键比较
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ToetsBijTrajectId that = (ToetsBijTrajectId) o;
        return Objects.equals(trajectId, that.trajectId) && Objects.equals(toetsId, that.toetsId);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(trajectId, toetsId);
    }
    
    // 生成getter和setter方法
}
  1. 修改ToetsBijTraject类,用@EmbeddedId关联主键类,再用@MapsId关联实体对象:
@Entity
@Table(name = "tt_traject_ref_toets")
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE, region="")
public class ToetsBijTraject implements Serializable, Comparable<ToetsBijTraject> {
    @EmbeddedId
    private ToetsBijTrajectId id;
    
    @ManyToOne
    @MapsId("trajectId") // 对应主键类里的trajectId字段
    @JoinColumn(name = "traject_id")
    private Traject traject;
    
    @ManyToOne
    @MapsId("toetsId") // 对应主键类里的toetsId字段
    @JoinColumn(name = "toets_id")
    private Toets toets;
    
    // 其他变量和方法保持不变
}

方案2:使用@IdClass

这种方式不需要嵌入式类,直接用一个普通的主键类:

  1. 创建主键类(同样要实现Serializable):
public class ToetsBijTrajectId implements Serializable {
    private Integer trajectId;
    private Integer toetsId;
    
    // 重写equals和hashCode方法
    // 生成getter和setter方法
}
  1. 修改ToetsBijTraject类:
@Entity
@Table(name = "tt_traject_ref_toets")
@IdClass(ToetsBijTrajectId.class)
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE, region="")
public class ToetsBijTraject implements Serializable, Comparable<ToetsBijTraject> {
    @Id
    @Column(name = "traject_id", columnDefinition = "int(10) unsigned")
    private Integer trajectId;
    
    @Id
    @Column(name = "toets_id", columnDefinition = "int(10) unsigned")
    private Integer toetsId;
    
    @ManyToOne
    @JoinColumn(name = "traject_id", insertable = false, updatable = false)
    private Traject traject;
    
    @ManyToOne
    @JoinColumn(name = "toets_id", insertable = false, updatable = false)
    private Toets toets;
    
    // 其他变量和方法保持不变
}

额外排查要点

  • 检查Hibernate方言:确保你的配置文件里用的是对应MySQL的方言,比如org.hibernate.dialect.MySQL8Dialect(MySQL8+)或者org.hibernate.dialect.MySQL5InnoDBDialect(MySQL5.x),方言错误会导致类型解析异常。
  • 清理缓存:重启应用或者清理Hibernate的二级缓存,避免旧的映射信息干扰。
  • 核对数据库连接URL:确认URL里没有添加影响类型映射的特殊参数,比如useOldAliasMetadataBehavior=true这类可能引发问题的配置。

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

火山引擎 最新活动