Hibernate5中自定义实体类与数据库命名规则的方法相比之前版本有较大改变,在hibernate5之前的版本实现NamingStrategy就可以实现自定义规则,hibernate5改为通过ImplicitNamingStrategy与PhysicalNamingStrategy实现。
关于ImplicitNamingStrategy与PhysicalNamingStrategy详细的解释可以看官方文档,也可以参考其它博文,这里不在详述,参考博文:Hibernate入门之命名策略(naming strategy)详解
简单介绍一下ImplicitNamingStrategy与PhysicalNamingStrategy
ImplicitNamingStrategy:隐式规则,如果实体类没有@Entity(name = "table_xxx")或@Column(name="column_xxx")等指定数据库表名或列名的话,ImplicitNamingStrategy有效,如果在注解中指定名称,则以注解为准。
PhysicalNamingStrategy:物理规则,不管有没有@Entity(name = "table_xxx")或@Column(name="column_xxx")等注解命名,都要按自定义的PhysicalNamingStrategy规则映射数据库名称。
下面用示例来说明实际使用方法
需求一:为了统一命名规范,强制要求数据库映射实体类属性字段使用驼峰命名,数据库字段使用下划线_命名,而又不想麻烦在实体类每个属性上都加上@Column(name="column_xxx")注解,而是没有注解的根据属性名自动映射数据库字段,有注解的则使用注解的名称映射,那么应该使用ImplicitNamingStrategy。
hibernate已经提供了多个ImplicitNamingStrategy的实现,我们基于其中一个实现ImplicitNamingStrategyJpaCompliantImpl来做扩展
public class MyImplicitNamingStrategy extends ImplicitNamingStrategyJpaCompliantImpl {
private static final long serialVersionUID = 1l;
@Override
public Identifier determineJoinTableName(ImplicitJoinTableNameSource source) {
String name = source.getOwningPhysicalTableName() + "_"
+ source.getAssociationOwningAttributePath().getProperty();
return toIdentifier(name, source.getBuildingContext());
}
/**
* 重写此方法实现,驼峰转_
*/
@Override
public Identifier determineBasicColumnName(ImplicitBasicColumnNameSource source) {
String name = transformAttributePath( source.getAttributePath() );
name = addUnderscores(name);
return toIdentifier( name, source.getBuildingContext() );
}
protected static String addUnderscores(String name) {
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().toLowerCase(Locale.ROOT);
}
}
只需要重写determineBasicColumnName(ImplicitBasicColumnNameSource source)方法即可实现改变列名命名规则
需求二:统一管理数据库表的前缀与后缀,如果在每个@Entity(name = "table_xxx")中都加上前后缀,会比较麻烦切不便于统一管理,那么可以通过自定义PhysicalNamingStrategy实现
hibernate依然提供了多个PhysicalNamingStrategy的实现,我们基于其中的PhysicalNamingStrategyStandardImpl来实现需求
public class MyPhysicalNamingStrategy extends PhysicalNamingStrategyStandardImpl {
private static final long serialVersionUID = 1l;
/**
* 数据库表前缀
*/
private String prefix;
/**
* 数据库表后缀
*/
private String suffix;
/**
* 数据库表前缀
*/
public String getPrefix() {
return prefix;
}
/**
* 数据库表前缀
*/
public void setPrefix(String prefix) {
this.prefix = prefix;
}
/**
* 数据库表后缀
*/
public String getSuffix() {
return suffix;
}
/**
* 数据库表后缀
*/
public void setSuffix(String suffix) {
this.suffix = suffix;
}
/**
* 重写方法实现自动追加前缀后缀
*/
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
StringBuilder nameSB = new StringBuilder();
if(!StringUtils.isEmpty(prefix)) {
nameSB.append(prefix);
}
nameSB.append(name.getText());
if(!StringUtils.isEmpty(suffix)) {
nameSB.append(suffix);
}
return new Identifier(nameSB.toString(), name.isQuoted());
}
}
重写toPhysicalTableName方法即可实现对表名的规则定制
使用方法
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.default_batch_fetch_size">16</prop>
</props>
</property>
<property name="implicitNamingStrategy" ref="myImplicitNamingStrategy" />
<property name="physicalNamingStrategy" ref="myPhysicalNamingStrategy" />
</bean>
<!-- 这里是自定义的两个类的bean -->
<bean id="myImplicitNamingStrategy"
class="com.test.MyImplicitNamingStrategy"/>
<bean id="myPhysicalNamingStrategy"
class="com.test.MyPhysicalNamingStrategy">
<property name="prefix" value="u_"/>
<property name="suffix" value="_s"/>
</bean>