JPA连接达梦数据库导致auto-ddl失效问题解决

现象:

项目使用了JPA,并且auto-ddl设置的为update,在连接达梦数据库的时候,第一次启动没有问题,但是后面重启就会报错,发现错误为重复建表,也就是说已经建好的表没有检测到,又重新走的建表流程。经过一天的排查,总结了2个解决方案。

问题的根源:

问题产生的原因是因为数据库实例设置了不区分大小写,并且在JPA的注解上的表名及字段名将表名都为小写时,在数据库创建的表名和字段名都为小写。在数据库连接后,会获取所有的表,和模型做匹配映射,没有映射的到的表会走创建表的流程,映射到的会走更新流程。但是在映射的过程中,达梦将映射部分强制设置为大写映射,并且这部分代码被写到了达梦的连接驱动内,很难进行扩展。这个映射部分源码要跟的很深,总的来说就是从数据库拿到的表名都是小写的,但是匹配的时候是将实体类上@Table的name值转为大写后再进行映射,而且这个是在达梦数据库的驱动里面设置的,重写方言的buildIdentifierHelper方法也没用。

而且这个方法的builder是在父类中直接build()的,又没法在父类执行完后扩展,只能在执行前扩展,所以设置的值没用。

解决办法:

1、达梦数据库创建数据库实例的时候使用默认的规则,区分大小写。不要创建不区分大小写的数据库实例,就不会有这个问题。并且记得在数据库连接里要设置参&ignoreCase=false&columnNameUpperCase=false

示例:jdbc:dm://{ip}:{port}/{数据库}?schema={schema}&useUnicode=true&serverTimezone=Asia/Shanghai&useSSL=false&characterEncoding=UTF-8&ignoreCase=false&columnNameUpperCase=false

2、匹配阶段不好解决,就在别的地方想想办法。问题的根源是因为实体类定义的大写表名和数据库中的小写表名匹配不上导致的,那就在建表阶段将表设置为大写就行了。而建表阶段的代码重新方言是可以做到的。

创建自定义的StandardTableExporter

java 复制代码
import org.hibernate.boot.Metadata;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.dialect.Dialect;
import org.hibernate.mapping.Table;
import org.hibernate.tool.schema.internal.StandardTableExporter;


public class DmStandardTableExporter extends StandardTableExporter {

    public DmStandardTableExporter(Dialect dialect) {
        super(dialect);
    }

    @Override
    public String[] getSqlCreateStrings(Table table, Metadata metadata, SqlStringGenerationContext context) {
        table.setName(table.getName().toUpperCase());
        return super.getSqlCreateStrings(table, metadata, context);
    }
}

重写达梦方言的getTableExporter方法

java 复制代码
import org.hibernate.dialect.DmDialect;


public class ZeusDmDialect extends DmDialect {
    
    //这里是你自定义的StandardTableExporter
    private DmStandardTableExporter tableExporter = new DmStandardTableExporter( this );

    @Override
    public DmStandardTableExporter getTableExporter() {
        return tableExporter;
    }
}

配置使用自己写的写的方言:

java 复制代码
spring:
  jpa:
    properties:
      hibernate:
        dialect: a.b.c.d.e.ZeusDmDialect #这里配置自己写的类的全路径名称,别照抄!!!

把数据库的之前创建的小写的表名的表全删了,多重启几次试试看,应该就解决问题了。

相关推荐
一个做软件开发的牛马2 小时前
Spring Boot 自动配置原理揭秘:从 @SpringBootApplication 到手写自定义 Starter
java·后端
迷枫7122 小时前
【无标题】
数据库
人道领域2 小时前
【LeetCode刷题日记】47.全排列Ⅱ
java·开发语言·算法·leetcode
TDengine (老段)3 小时前
TDengine 扫描算子 — TableScan、TagScan 与下推优化
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
放下华子我只抽RuiKe53 小时前
FastAPI 全栈后端(三):数据库与 ORM
前端·数据库·react.js·oracle·性能优化·前端框架·fastapi
是苏浙3 小时前
Java实现链表1
java·开发语言
未若君雅裁3 小时前
上传数据安全:对称加密、非对称加密、签名与重放防护
java·安全
可乐ea3 小时前
【Spring Boot + MyBatis|第7篇】JWT 登录认证与拦截器实现
java·spring boot·后端·mybatis·状态模式
BAGAE3 小时前
星链卫星数据获取:从太空安全到实时通信的技术革命
网络·数据结构·数据库·算法·云计算·hbase
zh_xuan3 小时前
Android导出并查看数据库
数据库·sqlite