首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

Hibernate 动态映射表的两种计策

2012-08-26 
Hibernate 动态映射表的两种策略通过Hibernate去处理一个配置文件对应多张表的情况,我整理了一下大概有两

Hibernate 动态映射表的两种策略

通过Hibernate去处理一个配置文件对应多张表的情况,我整理了一下大概有两种方式

一、通过实现命名策略接口NamingStrategy

? 以下是一个示例:

1、自定义一个类MyNamingStrategy来实现NamingStrategy。(这样你要实现10个方法,如果其他方法
不需要,我们可以通过继承它的一个适配器类DefaultNamingStrategy来只实现我们需要的方法)好了,我
们就继承DefaultNamingStrategy 吧。
2、实现public String classToTableName(String className)方法来实现自己命名策略。
我这的业务需要是每隔一个月就要换一个表。比如1月用biz_1,那么2月就用biz_2....但是这些表的结构是相同的。我们要做的就是通过获得月份来动态的选择表。我们从这个方法中这样写:
public class MyNamingStrategy extends DefaultNamingStrategy {
public static final MyNamingStrategy INSTANCE = new MyNamingStrategy();
public String classToTableName(String className) {
return "biz_" + Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
}
}

好了,这样就可以根据月份来动态的选择表名了。
3、使用命名策略。
要使用这个命名策略可以这样:
Configuration cfg = new Configuration()
.setNamingStrategy(MyNamingStrategy.INSTANCE)
.configure("hibernate.cfg.xml")
.addFile("biz.hbm.xml");
ok,这样就可以实现我们的动态表名映射啦!

二、通过SQLQuery实现要得到的效果

?

例如我有一个 pojo 是 ReadInfo,用来记录阅读信息的。由于数据量宠大,所以我的思路是按月划分,每个月一张表。所以只是表名不同,而字段是完全相同的。?ReadInfo.java 是这样的,其中 userId, year, month, day 是联合主键:
private Integer userId;    private Integer year;    private Integer month;    private Integer day;    private Integer point;
?

那么相应的 ReadInfo.hbm.xml 的片段是

??

<class name="ReadInfo" table="tblReadInfo" mutable="false">        <composite-id>            <key-property name="userId" column="userId" type="integer"/>            <key-property name="year" column="year" type="integer"/>            <key-property name="month" column="month" type="integer"/>            <key-property name="day" column="day" type="integer"/>        </composite-id>        <property name="point" column="point" type="integer"/>    </class>

?

上面的xml,注意 2 个细节

1. pojo 所映射的 table tblReadInfo 实际上是不存在的。实际的表是 tblRead200710 之类的;

2. mutable 要设置为?false,即是说,关闭 hibernate 对这个 pojo 的任何持久化操作,以避免 hibernate 把数据写到 tblReadInfo 中(这个表是不存在的嘛)。因此,所有的持久化操作,都是需要自己通过 SQLQuery 来处理。

现在可以看一下 ado 中的操作了,先看一个 select 操作

public ReadInfo selectReadInfo(Integer userId, Integer year,            Integer month, Integer day) throws HibernateException    {        ReadInfo readInfo = null;        Session session = getSession();        Transaction tx = session.beginTransaction();        try        {            String sql = "select * from tblRead"                + Misc.formatMoon(year, month)                + " where userId=? and day=?";            SQLQuery query = session.createSQLQuery(sql);            query.addEntity(ReadInfo.class);            query.setLong(0, userId);            query.setInteger(1, day);            readInfo = (ReadInfo) query.uniqueResult();            tx.commit();        }        catch (HibernateException e)        {            log.error("catch exception:", e);            if (tx != null)            {                tx.rollback();            }            throw e;        }        return readInfo;    }

?

上面的代码,关键是以下几点:

1. 通过函数参数的 year, month 来确定要操作的表名,我自己写了一个 Misc.formatMoon(year, month) 来生成 "yyyyMM" 格式的字串;

2. 使用了 SQLQuery ,再通过 query.addEntity(ReadInfo.class); 建立与 ReadInfo 的映射关系;

3. query.setXxx() 与 PreparedStatement 的类似,不过索引是从 0 开始;

4. 其它的就跟一般的 Query 操作类似的了。

再看一个 insert 操作

?

public void insertReadInfo(ReadInfo readInfo) throws HibernateException    {        Session session = getSession();        Transaction tx = session.beginTransaction();        try        {            String sql = "insert into tblRead"                + Misc.formatMoon(readInfo.getYear(), readInfo.getMonth())                + " (userId, year, month, day, point) values (?, ?, ?, ?, ?)";            SQLQuery query = session.createSQLQuery(sql);            query.setLong(0, readInfo.getUserId());            query.setInteger(1, readInfo.getYear());            query.setInteger(2, readInfo.getMonth());            query.setInteger(3, readInfo.getDay());            query.setInteger(4, readInfo.getPoint());            query.executeUpdate();            tx.commit();        }        catch (HibernateException e)        {            log.error("catch exception:", e);            if (tx != null)            {                tx.rollback();            }            throw e;        }    }

?

同理,update, delete 等操作也是这样实现的。

hmm.. 这种处理方式的麻烦的地方是需要手工写 sql ,因此要尽量写通用的标准 sql,不然在数据库兼容方面会有问题。当然,有时是会出现无法兼容的情况,那么可以考虑把 sql 写到配置文件中,根据不同的数据库,装载相应的配置文件。

?

参考文档:

http://www.cublog.cn/u1/50766/showart_400410.html

http://lorry1113.iteye.com/blog/430843

?

热点排行