hibernate跨数据库,columnDefinition不可移植性改造方案

背景&问题描述

很多项目选择jpa/hibernate,更多是为了代码的可移植性,不限制数据库的选择。特别是toB的业务系统,不同的客户,要求用不同的数据库。特别近几年,大力倡导软件国产化,国产数据库也在崛起,很多政府、国企、电力、银行在数据库的选择上,纷纷转向国产数据库。也许mybatis+mysql很香,但是代码可移植性却成了toB\toG软件类平台的关键竞争力。
hibernate,在字段定义,很多人都喜欢用columnDefinition注解去定义表的DDL,可能是曾经留下来的习惯吧。以前的hibernate对数据库字段及数据库移植性支持的比较差,像json、time、blob等一些特殊字段类型,表字段注释等支持的不好,为了方便,大家基本都会用columnDefinition注解直接去定义表,columnDefinition注解属性定义的ddl是不可移植性的,导致了整个项目不能跨数据库自动创建表。
下文讲解columnDefinition字段的替代方案。

解决方案

以mysql为例


@Colum(columnDefinition="decimal(15,2) comment '产品单价' default 1.5 ")

  • 字段注释
    需要将hibernate升级到5.6版本以上
    字段注释使用注解org.hibernate.annotations.Comment
    @Comment("产品单价")
  • 字段长度、精度
    字段长度使用javax.persistence.Column注解中的length属性,精度使用scale
    @Column(length=15,scale=2)
  • 字段默认值
    字段默认值使用org.hibernate.annotations.ColumnDefault注解
    注意:字符型,需要加单引号
    @ColumnDefault("1.5")
  • 大字段类型
    大字段处理用javax.persistence.Lob,同时加注解@javax.persistence.Basic(fetch = FetchType.LAZY)懒加载,避免加载大数据,导致性能很差
    对应数据库text\blob字段等
    @Column
    @Lob
    @Basic(fetch = FetchType.LAZY)
  • 时间类
    时间类型字段使用注解javax.persistence.Temporal
    通过传入注解参数TemporalType类型,可以指定时间类型
    image

@Temporal(TemporalType.TIMESTAMP) // 时间戳
@Temporal(TemporalType.DATE) // 日期
@Temporal(TemporalType.TIME) // 时间

  • json类型
    json数据,如果数据库不支持json类型,hibernate会默认转为varchar类型,并且长度默认为255,对于json数据,通常都是大字段,下期将改造方案。
@TypeDef(name = "json", typeClass = JsonStringType.class)
public class Test {
  @Type(type = "json")
  private TestModel testModel;
}

@Type(type = "json") 其含义是将当前表格列映射成“Hibernate Types”中的 JsonStringType类型。JsonStringType进一步将对应的数据实体映射成VARCHAR类型。

hibernate支持json字段类型,可参考
https://github.com/vladmihalcea/hibernate-types

注意事项

  • 汉字编码长度不同
    不同数据库编码对字符长度的定义不一致,比如,mysql,varchar(20)可以存放20个汉字,而sqlserver相同的字段定义只能存放10个汉字。建议在定义表字段时,取大不取小,考虑汉字占位符;
  • 参数限制
    传参不能超过2100条,条数不能超过1000条,in参数不能超过1000条(SqlServer、oracle都有这个限制)
    对于一些表参数传递,尽可能用关联查询,推荐使用querydsl做关联查询,避免大量参数传递
  • 唯一键名称重复限制
    mysql中,唯一键就是索引,在同一个表,索引名称不能重复,而SqlServer是有唯一键,是整库内,所有唯一键名称不能重复。建议在建唯一键时,不填写索引name,hibernate会自动生产不重复name
    @Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"name", "age"})})
posted @ 2023-03-06 10:15  ·志坚行远·  阅读(267)  评论(0编辑  收藏  举报