【问题标题】:Hibernate naming strategy for MariaDB (UPPER_SNAKE_CASE)MariaDB 的休眠命名策略 (UPPER_SNAKE_CASE)
【发布时间】:2020-01-30 22:31:39
【问题描述】:

在我的应用程序中,我使用 flyway 进行数据迁移,因此我在 UPPER_SNAKE_CASE 中定义了所有名称的所有表(例如 users -> USERS、candidateGroups -> CANDIDATE_GROUP)。我为不同的环境提供了 2 种配置:本地和 docker。在本地环境中我运行 h2,在 Docker 上我使用 MariaDB 运行。

现在在 h2 上运行时一切正常,在 MariaDB 上休眠是尝试对所有小写表执行操作,这会导致错误:

原因:java.sql.SQLException:表 'application.users' 不存在

经过一些调查,我尝试添加到我的application-docker.yml

  spring:
    jpa:
     hibernate:
       naming:
         physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

这会导致休眠中的表名大写: Caused by: java.sql.SQLException: Table 'application.Users' doesn't exist

我知道我可以使用注释 @Table(name = "USERS") 命名所有表并为所有列提供名称,但这不是我想要的解决方案。

不幸的是,我没有找到任何与我的案例相匹配的策略(我知道this 展示了如何创建自定义命名策略,但我认为我的案例并不常见),我应该为我的 MariaDB 配置使用什么命名策略符合我的情况?

【问题讨论】:

  • 解决这个问题的正确方法实际上是使用注释告诉 Hibernate 表名是什么。您也可以为此使用旧的 XML hbm 配置文件。
  • @TimBiegeleisen 但是为什么它与 h2 一起工作?它必须使用某种其他策略,这意味着除了注释之外的其他解决方案是可能的,您知道 h2 使用什么解决方案来解析名称吗?
  • H2 没有做任何事情,它是 Hibernate 的默认设置。问题是,每个数据库在区分大小写方面都不同。 MySQL 在 Linux 上默认区分大小写,但在 Windows 上不区分大小写。据说 H2 在任何地方都是区分大小写的。无论如何,您不应该依赖默认行为,因为它可能会在将来的某个时候中断。
  • 你的解释这个接缝很合理,但是如果 hibernate 在 h2 的情况下使用一些默认策略,那么如果我将此策略强制为所有类型的数据库的全局,那么它应该可以正常工作吗?还是我错过了什么?

标签: java spring hibernate jpa mariadb


【解决方案1】:

HibernateSpring Data JPA 中都没有 UPPER_SNAKE_CASE 命名策略,但可以通过扩展 PhysicalNamingStrategyStandardImplSpringPhysicalNamingStrategy 来定义自己的命名策略。

在 Spring Data JPA 中更容易,因为 Spring 已经将名称转换为蛇形大小写:

import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;

import java.io.Serializable;
import java.util.Locale;

public class UpperSnakeCaseSpringPhysicalNamingStrategyImpl extends SpringPhysicalNamingStrategy implements Serializable {

    @Override
    protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
        name = name.toUpperCase(Locale.ROOT);
        return new Identifier(name, quoted);
    }
}

对于转换为snake_case 的Hibernate 实现,需要至少覆盖​​5 个方法中的2 个:

import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;

import java.io.Serializable;
import java.util.Locale;

public class UpperSnakeCasePhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl implements Serializable {

    @Override
    public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
        return new Identifier(addUnderscores(name.getText()), name.isQuoted());
    }

    @Override
    public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
        return new Identifier(addUnderscores(name.getText()), name.isQuoted());
    }

    private static String addUnderscores(String name) {
        final StringBuilder buf = new StringBuilder(name.replace('.', '_'));
        for (int i = 1; i < buf.length() - 1; i++) {
            if (
                    Character.isLowerCase(buf.charAt(i - 1)) &&
                            Character.isUpperCase(buf.charAt(i)) &&
                            Character.isLowerCase(buf.charAt(i + 1))
            ) {
                buf.insert(i++, '_');
            }
        }
        return buf.toString().toUpperCase(Locale.ROOT);
    }
}

最后应该在application.properties或者application.yml中设置自定义的命名策略:

spring.jpa.hibernate.naming.physical-strategy=my.package.UpperSnakeCaseSpringPhysicalNamingStrategyImpl

关于 SO 的更多信息:


更新 (16.01.2020)

Naming Strategies in Hibernate 5

【讨论】:

    猜你喜欢
    • 2014-05-03
    • 1970-01-01
    • 2012-09-28
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多