hibernate实现动态表名
起因:
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方法就会被调用。
那么,如果服务器一直运行的好好的,到了新的月,得生成新表名了吧,这个时候难道需要重启服务器,难道每个月都重启一下服务器?我觉得很二。 于是我测了一下,很悲剧的发现,果然只在服务器启动的时候调用。不知道是不是我测得有问题,反正我觉得很二。
那这样其实也无法满足每个月动态更换表名的需求,需要建一个比较完善的建表策略了,等我们有了好的解决方案再发表上来吧。