? ? ?在《[一口一口吃掉Hibernate(一)——使用SchemaExport生成數據表](http://blog.csdn.net/xiaoxian8023/article/details/11669917)》中介紹了如何生成數據表。但是這只是最基本的。Hibernate在生成或者操作數據庫時,會受一些限制。比如一開始設計表的時候,直接寫成了user(id,name,password,createTime) ?這種格式的。但是客戶后來要求表名稱要以“t_”開頭,字段名要以“stu_”開頭,可以是一些數據庫的關鍵字,單詞之間以“_”隔開,方便他們維護.例如:T_User(stu_Id,stu_Name,stu_Create_Time)。
? ? 對于上面的問題,常規的方法就是去修改Hibernate_cfg.xml中的表,為每個表添加“t_”,或者寫table屬性,字段也重新使用column屬性來修改。如果你有100張表,每個表平均有10個字段,你還會去一個一個修改么?還有可能漏掉或者改錯。最“可惡”的是,如果客戶再讓你改成其他的呢,是不是還要全部修改一次?
? ? 有沒有一種方法,不修改原先的配置,添加并配置一下表和字段的前后綴及分隔符等等,既可以完成呢??經過嘗試,終于被我拿下了,現在拿出來與大家分享。
? ? 針對上述問題,我主要用的是NamingStrategy接口。這個接口很有意思,可以作為業務類規范和數據庫表規范的橋梁,它可以表和列的映射關系的轉變和處理。例如一個數據對象User,對應數據庫表是T_USER,如果所有映射關系都是這樣的情況,可以使用NamingStrategy做為一個橋梁銜接,而不用再hbm.xml映射文件中指定class對應的物理table。
? ? 先說一下Hibernate讀取映射文件的簡要過程:循環讀取class標簽,判斷class標簽的table屬性值是否為null,若為null,則調用NamingStrategy接口的classToTableName方法將class值轉換并處理(按命名策略NamingStrategy處理)的表名。若不為null,則說明設置了table,那么調用NamingStrategy接口的tableName方法獲取處理過的表名。循環遍歷property,判斷property標簽的column屬性值是否為null,若為null,則首先調用propertyToColumnName方法,將屬性值轉化為列名,再調用logicalColumnName方法。若不為null,則直接調用NamingStrategy接口的logicalColumnName方法,再調用columnName方法進行處理(按命名策略NamingStrategy處理)。
? ? 了解了上面說的這個過程,只要我們實現NamingStrategy這個接口,就可以隨心所欲的修改表映射了。不多說了,直接上代碼吧:
? 【MyNamingStrategy】自定義的命名策略,可對表、字段進行統一處理。
~~~
package com.tgb.hibernate.neatlyDB;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.util.StringHelper;
/**
* 數據庫命名策略,可定制表、字段等的前后綴
*
* @author Longxuan
*
*/
public class MyNamingStrategy implements NamingStrategy {
/**
* 數據庫命名策略單一實例
*/
private static MyNamingStrategy instance = null;
/**
* 數據庫配置信息類
*/
private static DatabaseConfiguration dbcfg = null;
/**
* 私有化構造方法
*/
private MyNamingStrategy() {
}
/**
* 使用單利模式,獲取數據庫命名策略的唯一實例
*
* @return
*/
public static synchronized MyNamingStrategy getInstance() {
// 默認讀取hibernate.cfg.xml文件
Configuration cfg = new Configuration().configure();
return getInstance(cfg);
}
/**
* 使用單利模式,獲取數據庫命名策略的唯一實例,同時使用默認Hibernate.cfg.xml更新命名策略信息
*
* @param cfg
* 配置文件信息
* @return
*/
public static synchronized MyNamingStrategy getInstance(Configuration cfg) {
if (instance == null) {
instance = new MyNamingStrategy();
}
MyNamingStrategy.dbcfg = new DatabaseConfiguration(cfg);
return instance;
}
/**
* 使用單利模式,獲取數據庫命名策略的唯一實例,同時更新命名策略信息
*
* @param cfg
* 配置文件信息
* @return
*/
public static synchronized MyNamingStrategy getInstance(
DatabaseConfiguration dbcfg) {
if (instance == null) {
instance = new MyNamingStrategy();
}
MyNamingStrategy.dbcfg = dbcfg;
return instance;
}
/**
* 設置或更新數據庫配置信息
*
* @param dbcfg
*/
public void setDBConfig(DatabaseConfiguration dbcfg) {
MyNamingStrategy.dbcfg = dbcfg;
}
/**
* 轉化為物理表名
*
* @param className hbm.xml中的對應表的class值
*/
@Override
public String classToTableName(String className) {
if(className == null ) return null;
//改變大小寫
String str =UpdateStyle(className,dbcfg.getTableStyle().name());
//添加前后綴
str = addPrefixORStuffix(str, dbcfg.getTablePrefix(),dbcfg.getTableSuffix());
//添加分隔符
str = addSeparator(str,dbcfg.getTableSeparator());
return str;
}
@Override
public String collectionTableName(String ownerEntity,
String ownerEntityTable, String associatedEntity,
String associatedEntityTable, String propertyName) {
return null;
}
/**
* 將讀取到的列名傳遞過來進行加工處理,變為物理表的字段名
*
* @param columnName logicalColumnName方法讀取到的列名
*/
@Override
public String columnName(String columnName) {
//先調用logicalColumnName方法,拿到處理過的值,
//再傳遞到該方法中,所以可以在這兩個方法中任一選擇修改。
//return columnName;
if(columnName == null ) return null;
//改變大小寫
String str =UpdateStyle(columnName,dbcfg.getColumnTyle().name());
//添加前后綴
str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());
//添加分隔符
str = addSeparator(str,dbcfg.getColumnSeparator());
return str;
}
/**
* 處理外鍵列名
*
*/
@Override
public String foreignKeyColumnName(String propertyName,
String propertyEntityName, String propertyTableName,
String referencedColumnName) {
if(referencedColumnName == null ) return null;
//改變大小寫
String str =UpdateStyle(referencedColumnName,dbcfg.getColumnTyle().name());
//添加前后綴
str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());
//添加分隔符
str = addSeparator(str,dbcfg.getColumnSeparator());
return str;
}
/**
* 關聯鍵的名稱
*/
@Override
public String joinKeyColumnName(String joinedColumn, String joinedTable) {
if(joinedColumn == null ) return null;
//改變大小寫
String str =UpdateStyle(joinedColumn,dbcfg.getColumnTyle().name());
//添加前后綴
str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());
//添加分隔符
str = addSeparator(str,dbcfg.getColumnSeparator());
return str;
}
@Override
public String logicalCollectionColumnName(String columnName,
String propertyName, String referencedColumn) {
return null;
}
@Override
public String logicalCollectionTableName(String tableName,
String ownerEntityTable, String associatedEntityTable,
String propertyName) {
return null;
}
/**
* 處理邏輯列名
* <b>若設置了column屬性,會直接調用調用該方法</b>
*
* @param columnName 列名
* @param propertyName 實體列名
*/
@Override
public String logicalColumnName(String columnName, String propertyName) {
//name值對應propertyName,column值對應columnName
//判斷columnName是否設置,若設置了,則返回column值,否則返回propertyName值
return columnName == null || columnName =="" ? propertyName:columnName;
}
/**
* 處理邏輯列名
* <b>若未設置column屬性,則先調用該方法,再調用logicalColumnName方法</b>
*
* @param propertyName 實體列名
*/
@Override
public String propertyToColumnName(String propertyName) {
if(propertyName == null ) return null;
//改變大小寫
String str =UpdateStyle(propertyName,dbcfg.getColumnTyle().name());
//添加前后綴
str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());
//添加分隔符
str = addSeparator(str,dbcfg.getColumnSeparator());
return str;
}
/**
* 處理表名
* <b>若設置了table屬性,才會調用該方法</b>
*/
@Override
public String tableName(String tableName) {
if(tableName == null ) return null;
//改變大小寫
String str =UpdateStyle(tableName,dbcfg.getTableStyle().name());
//添加前后綴
str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getTablePrefix(),dbcfg.getTableSuffix());
//添加分隔符
str = addSeparator(str,dbcfg.getTableSeparator());
return str;
}
/**
* 單詞分隔符
*
* @param name
* @return
*/
private String addSeparator(String str, String flag) {
StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));
for (int i = 1; i < buf.length() - 1; i++) {
if ('_' != buf.charAt(i - 1)
&& Character.isUpperCase(buf.charAt(i))
&& !Character.isUpperCase(buf.charAt(i + 1))) {
// buf.insert(i++, '_');
buf.insert(i++, flag);
}
}
return buf.toString();
}
/**
* 添加前后綴
*
* @param str
* 字符串
* @param prefix
* 前綴
* @param suffix
* 后綴
* @return
*/
private String addPrefixORStuffix(String str, String prefix, String suffix) {
StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));
buf.insert(buf.length(), suffix).insert(0, prefix);
return buf.toString();
}
/**
* 更新樣式
* @param str
* @param style
* @return
*/
private String UpdateStyle(String str, String style) {
if ("AU".equals(style)) {
str = str.toUpperCase();
} else if ("AL".equals(style)) {
str = str.toLowerCase();
} else if ("FU".equals(style)) {
StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));
String upper =buf.substring(0,1).toUpperCase();
buf.delete(0, 1).insert(0, upper);
str = buf.toString();
} else if ("FL".equals(style)) {
StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));
String lower =buf.substring(0,1).toLowerCase();
buf.delete(0, 1).insert(0, lower);
str = buf.toString();
} else{
}
return str;
}
}
~~~
【DatabaseConfiguration】數據庫樣式配置,包括前后綴、分隔符、大小寫等
~~~
package com.tgb.hibernate.neatlyDB;
import org.hibernate.cfg.Configuration;
/**
* 數據庫模式配置
* @author Longxuan
*
*/
public final class DatabaseConfiguration {
/**
* 列名樣式
* AU-all upper case
* AL-all lower case
* FU-first upper case per word
* FL-first lower case ,Other first letter upper case
*/
public static enum ColumnTyle {
AU,AL,FU,FL;
}
/**
* 表名稱樣式
* AU-all upper case
* AL-all lower case
* FU-first upper case per word
* FL-first lower case ,Other first letter upper case
*/
public static enum TableStyle{
AU,AL,FU,FL;
}
/**
* 列名樣式
* AU-all upper case
* AL-all lower case
* FU-first upper case per word
* FL-first lower case ,Other first letter upper case
*/
private ColumnTyle columnTyle = ColumnTyle.FL;
/**
* 表名稱樣式
* AU-all upper case
* AL-all lower case
* FU-first upper case per word
* FL-first lower case ,Other first letter upper case
*/
private TableStyle tableStyle = TableStyle.FU;
/**
* 表名稱前綴
*/
private String tablePrefix = "";
/**
* 表名稱后綴
*/
private String tableSuffix = "";
/**
* 表名稱分隔符
*/
private String tableSeparator = "";
/**
* 列名前綴
*/
private String columnPrefix = "";
/**
* 列名后綴
*/
private String columnSuffix = "";
/**
* 列名分隔符
*/
private String columnSeparator = "";
public ColumnTyle getColumnTyle() {
return columnTyle;
}
public void setColumnTyle(ColumnTyle columnTyle) {
this.columnTyle = columnTyle;
}
public TableStyle getTableStyle() {
return tableStyle;
}
public void setTableStyle(TableStyle tableStyle) {
this.tableStyle = tableStyle;
}
public String getTablePrefix() {
return tablePrefix;
}
public void setTablePrefix(String tablePrefix) {
this.tablePrefix = tablePrefix;
}
public String getTableSuffix() {
return tableSuffix;
}
public void setTableSuffix(String tableSuffix) {
this.tableSuffix = tableSuffix;
}
public String getTableSeparator() {
return tableSeparator;
}
public void setTableSeparator(String tableSeparator) {
this.tableSeparator = tableSeparator;
}
public String getColumnPrefix() {
return columnPrefix;
}
public void setColumnPrefix(String columnPrefix) {
this.columnPrefix = columnPrefix;
}
public String getColumnSuffix() {
return columnSuffix;
}
public void setColumnSuffix(String columnSuffix) {
this.columnSuffix = columnSuffix;
}
public String getColumnSeparator() {
return columnSeparator;
}
public void setColumnSeparator(String columnSeparator) {
this.columnSeparator = columnSeparator;
}
/**
* 初始化,讀取配置參數,默認讀取Hibernate.cfg.xml
* @param cfg
*/
public DatabaseConfiguration(){
ReadConfig(new Configuration().configure());
}
/**
* 初始化,讀取配置文件
* @param cfg
*/
public DatabaseConfiguration(Configuration cfg){
ReadConfig(cfg);
}
/**
* 自動讀取配置信息
* @param cfg
*/
private void ReadConfig(Configuration cfg){
tableStyle = cfg.getProperty("tablestyle")==""?TableStyle.FU:TableStyle.valueOf(cfg.getProperty("tablestyle"));
tablePrefix = cfg.getProperty("tablePrefix");
tableSuffix = cfg.getProperty("tablesuffix");
tableSeparator = cfg.getProperty("tableseparator");
columnTyle = cfg.getProperty("columntyle")==""?ColumnTyle.FL:ColumnTyle.valueOf(cfg.getProperty("columntyle"));
columnPrefix = cfg.getProperty("columnPrefix");
columnSuffix = cfg.getProperty("columnsuffix");
columnSeparator = cfg.getProperty("columnseparator");
}
}
~~~
【hibernate.cfg.xml】設置數據庫樣式配置信息
~~~
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory name="foo">
<!--
name: 配置的名稱
style: 類型 枚舉AU-all upper case
AL-all lower case
FU-first letter upper case per word
FL-first letter lower case ,Other first letters upper case
befix: 前綴
suffix: 后綴
separator: 分隔符
-->
<property name="tablestyle">FU</property>
<property name="tablePrefix" >T_</property>
<property name="tablesuffix" ></property>
<property name="tableseparator" >_</property>
<property name="columntyle">FU</property>
<property name="columnPrefix">[stu_</property>
<property name="columnsuffix">]</property>
<property name="columnseparator">_</property>
<property name="hibernate.dialect" >org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property><!-- 設置是否顯示生成sql語句 -->
<property name="hibernate.format_sql">false</property><!-- 設置是否格式化sql語句-->
<mapping resource="com/bjpowernode/hibernate/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
~~~
【User.hbm.xml】映射文件可以比較隨意的修改或者設定了
~~~
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.User" table="Users">
<id name="id" column="pid">
<generator class="uuid" />
</id>
<property name="name" column="userName"></property>
<property name="password" column="pwd"></property>
<property name="createTime"></property>
<property name="expireTime"></property>
</class>
</hibernate-mapping>
~~~
最后修改一下【ExportDB】,主要是修改必須先設置NamingStrategy,在調用configure方法
~~~
package com.bjpowernode.hibernate;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import com.tgb.hibernate.neatlyDB.DatabaseConfiguration;
import com.tgb.hibernate.neatlyDB.MyNamingStrategy;
/**
* 將hbm生成ddl
* @author Longxuan
*
*/
public class ExportDB {
/**
* @param args
*/
public static void main(String[] args) {
//默認讀取hibernate.cfg.xml文件,并按照命名策略修改表、字段的名稱
//Configuration cfg = new Configuration().configure();
//注意,必須先設置NamingStrategy,在調用configure方法
Configuration cfg = new Configuration().setNamingStrategy(MyNamingStrategy.getInstance()).configure();
SchemaExport export = new SchemaExport(cfg);
//true 在控制臺打印ddl語句,true 導入ddl語句到數據庫,即可執行
export.create(true, true);
}
}
~~~
? ? 看一下結果圖吧:表名,字段名都已經修改過了。

? ? 上面演示的是生成數據表。在對數據庫的增刪改查時,只要同樣設置NamingStrategy即可。
? ? 為了大家更為方便的使用,已經做成jar包分享給大家了,[點這里](http://pan.baidu.com/share/link?shareid=1107664883&uk=1259218556)下載。
- 前言
- Struts 簡單小結
- 深入淺出了解Struts的處理流程(有圖有真相)
- struts標簽+jstl標簽之國際化實例
- 一口一口吃掉Hibernate(二)——別被世俗蒙蔽了雙眼:Hibernate中Session之get和load方法的真正區別
- 一口一口吃掉Hibernate(一)——使用SchemaExport生成數據表
- 一口一口吃掉Hibernate(三)——Hibernate給表和字段設置前后綴及分隔符
- 一口一口吃掉Hibernate(四)——多對一單向關聯映射
- 一口一口吃掉Hibernate(五)——一對多單向關聯映射
- 一口一口吃掉Hibernate(六)——多對多關聯映射
- 一口一口吃掉Hibernate(七)——繼承映射
- 一口一口吃掉Hibernate(八)——Hibernate中inverse的用法
- 一覽Spring全貌
- 包辦婚姻的Spring IoC
- 3幅圖讓你了解Spring AOP
- Spring Aop實例之xml配置
- Spring Aop實例之AspectJ注解配置