从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);
验证要点
- 隐式命名验证:无
@Table注解的实体类,生成的表名应为驼峰转大写下划线格式 - 显式命名验证:带有
@Table(name="EXPLICIT_TABLE")或@Column(name="EXPLICIT_COL")的实体,数据库中名字与注解完全一致 - 关联对象验证:集合表、外键列、关联列的命名规则与原项目完全匹配
内容的提问来源于stack exchange,提问作者quarkpt
相关产品推荐
相关产品推荐

