起因:
mysql數據庫中生成的表有的名字是大寫,有的是小寫,有的和類名相同,有的后面加了日期,也就是所謂的動態表名,每月都會自動產生一個新的表。
環境:
mysql5.5+hibernate3
分析:
當然我是菜鳥,直接不知道原因,通過對比發現了原因。需要解決的問題其實有以下幾個:
類怎么和表名對應 表名大小寫怎么產生的 如何產生動態的表名 解決:
第一個問題類怎么和表名對應:
hibernate.cfg.xml 中添加類對應的配置文件,在這個Player.hbm.xml的配置最重要。
<mapping resource="com/joyfort/nova/persist/hibernate/game/model/Player.hbm.xml" />
看一下Player.hbm.xml內容,這個里面的table指定的就是表名,如果這里你不指定表名,則class標簽對應的類名就是表名
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Mapping file autogenerated by MyEclipse Persistence Tools -->
<hibernate-mapping>
<class name="com.joyfort.nova.persist.hibernate.game.model.Player" table="player">
<id name="uid" type="java.lang.String">
<column name="uid" />
<generator class="uuid.hex" />
</id>
<property name="username" type="java.lang.String">
<column name="username" length="50" unique="true" />
</property>
</class>
</hibernate-mapping>
第二個問題表名大小寫怎么產生的: 在第一個里面,假如我們在Player.hbm.xml配置文件里邊沒有指定table,那么表名就是你的類名,我們用的系統是Win7,mysql的配置也是默認的,這個時候產生的表名是Player。
也就是說表名大小寫和三個因素有關:你的系統,mysql配置,你的類名。
大寫的表名對我們的程序調用肯定會用影響,我們最好全部變為小寫的,便於在任何操作系統下使用。
關於這個的解決方法http://hi.baidu.com/virackt/item/ec94abd780b60f1fe0f46f1c 這篇文章說的比較詳細。
簡單來說就是:
在MySQL的配置文件中my.ini [mysqld] 中增加一行
lower_case_table_names = 1
參數解釋:
0:區分大小寫
1:不區分大小寫
第三個問題如何產生動態的表名
這個問題,是第一個和第二個的升華我覺得。我們已經明白如果在Player.hbm.xml配置文件里邊已經指定table了,那肯定產生的是一個固定名稱的表了。
所以要產生動態表名的前提肯定是我們不在配置文件中指定table值。那我們就需要了解hibernate產生表的原理了。
Hibernate中的NamingStrategy可以實現這個功能,它是用來定義表名和列名映射規則的一個接口。我們可以通過實現這個接口實現生成動態表名的這個命名策略。這個接口包含十個方法,其中的classToTableName(String className)是通過類名來映射表名的。我們實現這個方法就可以了。
1、自定義一個類LogsNamingStrategy繼承適配器類DefaultNamingStrategy。
2、實現public String classToTableName(String className)方法來實現自己命名策略,這個方法里面的內容我們根據自己的需求隨便設定即可。
public class LogsNamingStrategy extends DefaultNamingStrategy {
/** * */
private static final long serialVersionUID = 1L;
public static final LogsNamingStrategy INSTANCE = new LogsNamingStrategy();
public static List<String> SUBMETER_TABLE = new ArrayList<String>();
static{
SUBMETER_TABLE.add(LogBuy.class.toString());
SUBMETER_TABLE.add(LogChat.class.toString());
SUBMETER_TABLE.add(LogBattleresult.class.toString());
SUBMETER_TABLE.add(LogMsgAction.class.toString());
}
private static String TABLE_NAME = DateUtil.getDateStr(new Date(), "yyyy_MM");
@Override
public String classToTableName(String className) {
if(SUBMETER_TABLE.contains("class "+className)){
return super.classToTableName(className)+"_"+TABLE_NAME.toLowerCase();
}
return super.classToTableName(className).toLowerCase();
}
}
3、將這個策略即LogsNamingStrategy配置進程序,即在創建hibernate的Configuration對象時調用我們自己實現的LogsNamingStrategy命名策略。
Configuration configuration = new Configuration().setNamingStrategy(LogsNamingStrategy.INSTANCE)
不過還有一點不明白,現在我能看到的是,服務器啟動時,假如沒這個表,hibernate配置文件中是這樣的:
<property name="hibernate.hbm2ddl.auto">create</property>
那么,啟動服務器的時候,classToTableName方法就會被調用。
那么,如果服務器一直運行的好好的,到了新的月,得生成新表名了吧,這個時候難道需要重啟服務器,難道每個月都重啟一下服務器?我覺得很二。 於是我測了一下,很悲劇的發現,果然只在服務器啟動的時候調用。不知道是不是我測得有問題,反正我覺得很二。
那這樣其實也無法滿足每個月動態更換表名的需求,需要建一個比較完善的建表策略了,等我們有了好的解決方案再發表上來吧。