You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从Hibernate NamingStrategy迁移至支持策略的技术咨询

Hibernate 废弃 NamingStrategy 迁移方案

问题背景

维护的老Java项目中使用了自定义的ZiggyNamingStrategy实现Hibernate命名策略,但该接口已被废弃,需要迁移至官方支持的ImplicitNamingStrategy + PhysicalNamingStrategy方案,确保原有命名规则完全保留:

  • 隐式命名(无@Table/@Column等注解):驼峰转大写下划线格式
  • 显式命名(注解指定的名字):不做修改
  • 集合表、外键、关联列等遵循原有拼接规则

迁移思路

Hibernate将原NamingStrategy的职责拆分为两个独立接口:

  • ImplicitNamingStrategy:负责生成逻辑命名(即未通过注解显式指定时,根据实体类、属性生成的中间名称)
  • PhysicalNamingStrategy:负责将逻辑命名转换为数据库实际使用的物理命名(格式转换,比如驼峰转下划线)

通过分别实现这两个接口,完全复刻原ZiggyNamingStrategy的所有行为。

代码实现

1. 实现 ImplicitNamingStrategy

负责生成符合原规则的逻辑名,继承官方默认实现ImplicitNamingStrategyJpaCompliantImpl并按需重写方法:

package gov.nasa.ziggy.services.database;

import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.ImplicitCollectionColumnNameSource;
import org.hibernate.boot.model.naming.ImplicitCollectionTableNameSource;
import org.hibernate.boot.model.naming.ImplicitForeignKeyNameSource;
import org.hibernate.boot.model.naming.ImplicitJoinColumnNameSource;
import org.hibernate.boot.model.naming.ImplicitJoinTableNameSource;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl;
import org.hibernate.internal.util.StringHelper;

public class ZiggyImplicitNamingStrategy extends ImplicitNamingStrategyJpaCompliantImpl {

    public static final ZiggyImplicitNamingStrategy INSTANCE = new ZiggyImplicitNamingStrategy();

    // 对应原classToTableName:生成实体类对应的逻辑表名
    @Override
    public Identifier determinePrimaryTableName(org.hibernate.boot.model.naming.ImplicitEntityNameSource source) {
        String className = StringHelper.unqualify(source.getEntityNaming().getEntityName());
        return toIdentifier(className, source.getBuildingContext());
    }

    // 对应原propertyToColumnName:生成属性对应的逻辑列名
    @Override
    public Identifier determineBasicColumnName(org.hibernate.boot.model.naming.ImplicitBasicColumnNameSource source) {
        String propertyName = StringHelper.unqualify(source.getAttributePath().getFullPath());
        return toIdentifier(propertyName, source.getBuildingContext());
    }

    // 对应原collectionTableName:生成集合关联表的逻辑名
    @Override
    public Identifier determineJoinTableName(ImplicitJoinTableNameSource source) {
        String ownerTableName = source.getOwningPhysicalTableName().getText();
        String propertyName = StringHelper.unqualify(source.getAssociationAttributePath().getFullPath());
        String joinTableName = ownerTableName + "_" + propertyName;
        return toIdentifier(joinTableName, source.getBuildingContext());
    }

    // 对应原foreignKeyColumnName:生成外键的逻辑名
    @Override
    public Identifier determineForeignKeyName(ImplicitForeignKeyNameSource source) {
        String propertyTableName = source.getTableName().getText();
        String referencedColumnName = source.getReferencedColumnName().getText();
        String fkName = propertyTableName + "_" + referencedColumnName;
        return toIdentifier(fkName, source.getBuildingContext());
    }

    // 对应原joinKeyColumnName:生成关联列的逻辑名
    @Override
    public Identifier determineJoinColumnName(ImplicitJoinColumnNameSource source) {
        String joinedTable = source.getReferencedTableName().getText();
        String joinedColumn = source.getReferencedColumnName().getText();
        String joinColumnName = joinedTable + "_" + joinedColumn;
        return toIdentifier(joinColumnName, source.getBuildingContext());
    }

    // 对应原logicalCollectionTableName:生成集合表的逻辑名
    @Override
    public Identifier determineCollectionTableName(ImplicitCollectionTableNameSource source) {
        String ownerTableName = source.getOwningPhysicalTableName().getText();
        String associatedTableName = source.getAssociatedPhysicalTableName() != null
                ? source.getAssociatedPhysicalTableName().getText()
                : StringHelper.unqualify(source.getCollectionAttributePath().getFullPath());
        String collectionTableName = ownerTableName + "_" + associatedTableName;
        return toIdentifier(collectionTableName, source.getBuildingContext());
    }

    // 对应原logicalCollectionColumnName:生成集合列的逻辑名
    @Override
    public Identifier determineCollectionColumnName(ImplicitCollectionColumnNameSource source) {
        if (source.getExplicitColumnName() != null) {
            return source.getExplicitColumnName();
        }
        String propertyName = StringHelper.unqualify(source.getCollectionAttributePath().getFullPath());
        String referencedColumn = source.getReferencedColumnName().getText();
        String columnName = propertyName + "_" + referencedColumn;
        return toIdentifier(columnName, source.getBuildingContext());
    }
}

2. 实现 PhysicalNamingStrategy

负责将逻辑名转换为数据库物理名,复用原addUnderscores方法:

package gov.nasa.ziggy.services.database;

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

import gov.nasa.ziggy.util.StringUtils;
import gov.nasa.ziggy.util.StringUtils.TextCase;

public class ZiggyPhysicalNamingStrategy extends PhysicalNamingStrategyStandardImpl {

    public static final ZiggyPhysicalNamingStrategy INSTANCE = new ZiggyPhysicalNamingStrategy();

    // 转换逻辑表名为物理表名
    @Override
    public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
        String transformedName = addUnderscores(name.getText());
        return Identifier.toIdentifier(transformedName, name.isQuoted());
    }

    // 转换逻辑列名为物理列名
    @Override
    public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
        String transformedName = addUnderscores(name.getText());
        return Identifier.toIdentifier(transformedName, name.isQuoted());
    }

    // 复用原ZiggyNamingStrategy的驼峰转下划线逻辑
    protected String addUnderscores(String original) {
        return StringUtils.camelCaseToUnderscores(original, TextCase.UPPER);
    }
}

配置生效

根据项目类型配置Hibernate使用新的命名策略:

Spring Boot 项目

在application.properties中添加:

spring.jpa.hibernate.naming.implicit-strategy=gov.nasa.ziggy.services.database.ZiggyImplicitNamingStrategy
spring.jpa.hibernate.naming.physical-strategy=gov.nasa.ziggy.services.database.ZiggyPhysicalNamingStrategy

原生 Hibernate 配置

在Configuration中设置:

Configuration configuration = new Configuration();
configuration.setImplicitNamingStrategy(ZiggyImplicitNamingStrategy.INSTANCE);
configuration.setPhysicalNamingStrategy(ZiggyPhysicalNamingStrategy.INSTANCE);

验证要点

  1. 隐式命名验证:无@Table注解的实体类,生成的表名应为驼峰转大写下划线格式
  2. 显式命名验证:带有@Table(name="EXPLICIT_TABLE")或@Column(name="EXPLICIT_COL")的实体,数据库中名字与注解完全一致
  3. 关联对象验证:集合表、外键列、关联列的命名规则与原项目完全匹配

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 22:45:36