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>