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 #这里配置自己写的类的全路径名称,别照抄!!!

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

相关推荐
ZC跨境爬虫7 分钟前
LeetCode 27. 移除元素(双指针详解 + Java Python 多解法对比)
java·python·leetcode
逐米时代27 分钟前
智能招聘与人岗匹配:可解释匹配让录用依据有迹可循
大数据·数据库·人工智能
kisbad1 小时前
Day 036|OpenAI Agents SDK 快速开始:今天跑通第一个 Agent
java·前端·javascript
憧憬成为java架构高手的小白1 小时前
langchain4j框架学习
java
IvorySQL1 小时前
PostgreSQL 日报| RI 快速路径并发读取缺陷(8 月 13 日)
数据库·postgresql
0x531 小时前
Java网络编程(四)
java·网络
ly76891 小时前
Java 设计模式详解:从原则到 23 种经典模式
java·开发语言·设计模式
highreport1 小时前
HighReport报表工具定时调度和邮件定时发送
运维·服务器·数据库
01_ice2 小时前
数据库基础
数据库
萧瑟余晖2 小时前
Java深入解析篇三十之Java日志框架
java·开发语言