1. 概述
Hibernate 5 提供了两种命名策略:隐式命名策略(Implicit Naming Strategy) 和 物理命名策略(Physical Naming Strategy)。
在本篇文章中,我们将探讨如何通过这两种策略来自定义实体类映射到数据库表和字段的名称。
如果你对 Hibernate 还不太熟悉,建议先阅读我们的 Hibernate 入门指南。
2. 依赖配置
我们使用 Hibernate Core 依赖进行演示:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.24.Final</version>
</dependency>
3. 隐式命名策略
Hibernate 使用逻辑名称(logical name)将实体类或属性映射为数据库中的表或列。这个逻辑名称可以通过两种方式定义:
- ✅ 自动推导:由
ImplicitNamingStrategy
自动生成 - ✅ 显式指定:通过注解(如
@Table
、@Column
)手动设置
Hibernate 内置了四种 ImplicitNamingStrategy
实现,也可以自定义。
默认使用的是 ImplicitNamingStrategyJpaCompliantImpl
策略,它会保持 Java 类名和属性名与逻辑名称一致。
举个例子:
@Entity
@Table(name = "Customers")
public class Customer {
@Id
@GeneratedValue
private Long id;
private String firstName;
private String lastName;
@Column(name = "email")
private String emailAddress;
// getters and setters
}
此时的逻辑名称如下所示:
Customer -> Customers
firstName -> firstName
lastName -> lastName
emailAddress -> email
4. 物理命名策略
逻辑名称只是中间产物,真正用于数据库操作的是物理名称(physical name)。物理命名策略负责将逻辑名称转换成最终的 SQL 表名和列名。
默认情况下,物理名称等于逻辑名称。但如果想统一处理命名风格(比如从驼峰转下划线),就需要自定义 PhysicalNamingStrategy
。
下面是一个将驼峰命名转为下划线命名的实现:
public class CustomPhysicalNamingStrategy implements PhysicalNamingStrategy {
@Override
public Identifier toPhysicalCatalogName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
@Override
public Identifier toPhysicalColumnName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
@Override
public Identifier toPhysicalSchemaName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
@Override
public Identifier toPhysicalSequenceName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
@Override
public Identifier toPhysicalTableName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
private Identifier convertToSnakeCase(final Identifier identifier) {
final String regex = "([a-z])([A-Z])";
final String replacement = "$1_$2";
final String newName = identifier.getText()
.replaceAll(regex, replacement)
.toLowerCase();
return Identifier.toIdentifier(newName);
}
}
然后告诉 Hibernate 使用这个策略:
hibernate.physical_naming_strategy=com.baeldung.hibernate.namingstrategy.CustomPhysicalNamingStrategy
应用该策略后,上面的 Customer
实体对应的物理名称如下:
Customer -> customers
firstName -> first_name
lastName -> last_name
emailAddress -> email
⚠️ 注意:虽然 emailAddress
被显式标注为 "email"
,但由于未使用驼峰结构,所以不会被进一步转换。
5. 引号标识符(Quoted Identifiers)
SQL 中某些关键字(如 table
、order
等)是保留字,不能直接作为表名或列名使用。如果非要使用,就需要“引号转义”。
5.1. 手动使用双引号转义
@Entity(name = "Table")
@Table(name = "\"Table\"")
public class Table {
@Id
@GeneratedValue
private Long id;
@Column(name = "\"catalog\"")
private String catalog;
@Column(name = "\"schema\"")
private String schema;
private String name;
//Getters and setters
}
5.2. 使用 Hibernate 特有的反引号转义
@Entity(name = "Table")
@Table(name = "`Table`")
public class Table {
@Id
@GeneratedValue
private Long id;
@Column(name = "`catalog`")
private String catalog;
@Column(name = "`schema`")
private String schema;
@Column(name = "`name`")
private String name;
//Getters and setters
}
5.3. 全局启用引号转义
可以通过设置以下属性让 Hibernate 对所有标识符自动加引号:
hibernate.globally_quoted_identifiers=true
⚠️ 如果你在自定义的 CustomPhysicalNamingStrategy
中需要保留引号状态,请这样写:
Identifier.toIdentifier(newName, identifier.isQuoted());
6. 总结
本文介绍了 Hibernate 5 中两种核心命名策略的作用机制及使用方法:
- ✅ 隐式命名策略用于生成逻辑名称
- ✅ 物理命名策略用于将逻辑名称映射为实际数据库中的名称
- ✅ 可以通过注解覆盖默认行为
- ✅ 可自定义策略统一处理命名格式(如驼峰转下划线)
- ✅ 引号机制可解决关键字冲突问题
完整代码示例可在 GitHub 项目 中查看。