本次示例的项目中,定义了如下两个实体:

@Data
@Entity
public class Teacher {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

@Column(name = "Name")
private String name;

}
@Data
@Entity
@Table(name = "teacher_class")
public class TeacherClass {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

private Integer teacherId;

@Column(name = "ClassName")
private String className;

}

先来看看 JPA 默认的命名策略,我们可以显示配置如下:

spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
show-sql: true
hibernate:
ddl-auto: create
naming:
# 1. 表名及字段全小写下划线分隔命名策略(默认)
physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
Hibernate: create table teacher (id integer not null auto_increment, name varchar(255), primary key (id)) engine=InnoDB
Hibernate: create table teacher_class (id integer not null auto_increment, class_name varchar(255), teacher_id integer, primary key (id)) engine=InnoDB

运行项目,通过数据库或输出的SQL语句,默认策略的表现为:表名及字段全小写,并以下划线分隔

此外,引入的 Hibernate 还提供了另外一种物理命名策略,先进行如下配置,再来观察结果:

spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
show-sql: true
hibernate:
ddl-auto: create
naming:
# 2. 物理命名策略,未定义 @Table 和 @Column 将以实体名和属性名作为表名及字段名
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
Hibernate: create table Teacher (id integer not null auto_increment, Name varchar(255), primary key (id)) engine=InnoDB
Hibernate: create table teacher_class (id integer not null auto_increment, ClassName varchar(255), teacherId integer, primary key (id)) engine=InnoDB

以上表明,Hibernate 提供的命名策略是以实体名和属性名分别作为表名及字段名,但如果有定义 @Table@Column ,则以该属性值进行映射命名

当然,某些场景下,可以通过自定义命名策略来简化操作,或实现自身特定的业务,例如:假设需要为未定义 @Table 实体加上表前缀 tb_,或是以大写字母下划线来分隔定义字段(简单起见,以下配置并不直接实现 PhysicalNamingStrategy):

public class CustomNamingStrategyConfig extends SpringPhysicalNamingStrategy {

/**
* 配置映射的数据表名
*
* @param name
* @param jdbcEnvironment
* @return
*/
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironment) {
if (name == null) {
return null;
}
// 实体名 or 自定义的@Tabel name属性值
String text = name.getText();

// 首字母大写(类名),实体未定义@Table, 为表名加上tb_前缀
if (Character.isUpperCase(text.charAt(0))) {
final String tb = "tb_";
if (!text.contains(tb)) {
text = "tb" + text;
}

StringBuilder builder = new StringBuilder(text.replace('.', '_'));
for (int i = 1, maxLength = builder.length() - 1; i < maxLength; i++) {
if (this.isUnderscoreRequired(builder.charAt(i - 1), builder.charAt(i), builder.charAt(i + 1))) {
builder.insert(i++, '_');
}
}
return super.getIdentifier(builder.toString(), name.isQuoted(), jdbcEnvironment);
} else {
// 实体定义了@Table(name="xxx"),以name属性值为表名
return super.getIdentifier(text, name.isQuoted(), jdbcEnvironment);
}
}

/**
* 判断是否前一个字符为小写字母,当前字符为大写字母,下一个字符为小写字母
*
* @param before
* @param current
* @param after
* @return
*/
private boolean isUnderscoreRequired(char before, char current, char after) {
return Character.isLowerCase(before) && Character.isUpperCase(current) && Character.isLowerCase(after);
}

/**
* 配置映射的字段名
*
* @param name
* @param jdbcEnvironment
* @return
*/
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment jdbcEnvironment) {
// 实体的属性名 or 自定义的@Column name属性值
String text = name.getText();

if (Character.isUpperCase(text.charAt(0))) {
// 大写字母下划线分隔命名策略,有在实体字段上自定义@Column(name="Xx_Xxx")
return new Identifier(text, name.isQuoted());
} else {
// 常见的小写驼峰式命名策略
return super.toPhysicalColumnName(name, jdbcEnvironment);
}
}

}

application.yml 中修改如下配置:

spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
show-sql: true
hibernate:
ddl-auto: create
naming:
# 3. 自定义的命名策略
physical-strategy: cn.mariojd.jpa.naming.config.CustomNamingStrategyConfig
```

启动项目,查看结果,符合以上预设的实现要求

``` sql
Hibernate: create table tb_teacher (id integer not null auto_increment, Name varchar(255), primary key (id)) engine=InnoDB
Hibernate: create table teacher_class (id integer not null auto_increment, ClassName varchar(255), teacher_id integer, primary key (id)) engine=InnoDB

示例源码
欢迎关注我的个人公众号:超级码里奥
如果这对您有帮助,欢迎点赞和分享,转载请注明出处

最后更新: 2019年02月19日 11:37

原始链接: https://blog.mariojd.cn/custom-database-naming-strategy-for-jpa.html

× 支持创作
打赏二维码