当前位置: 代码迷 >> SQL >> 施用hibernate SQLQuery实现动态表
  详细解决方案

施用hibernate SQLQuery实现动态表

热度:39   发布时间:2016-05-05 12:58:31.0
使用hibernate SQLQuery实现动态表
我在实际的项目应用中,有时会设计出这样的一种数据表,每个时间段产生一个新表,例如是按年或月或日。相同类型的表中,所有的字段结构都是一样的。而 hibernate 提供的类与表的映射,是只能映射到一个具体表的,在程序的运行过程中,很难去动态修改一个 hbm 对应的表名。我在网上也有看到一实现,但是很复杂,并且不符合我的要求。
因此我就想到直接用 jdbc 去操作数据库,这样的做法是绕过 hibernate 了。方法是从 hibernate 的 session 中,直接取得数据库 connection ,然后就直接 jdbc 了。
后来在升级了 proxool 到 9.0RC3 后,发现居然出现了数据库连接无法释放的问题。为了解决这个问题,我查阅了 hibernate doc。我发现原来用 SQLQuery 可以更好的解决,并且可以重新用于 hibernate hbm 机制。以下举例说明。
例如我有一个 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 写到配置文件中,根据不同的数据库,装载相应的配置文件咯。

1 楼 marssstone 2008-09-16  
楼主能否发份代码,感激不尽

邮箱 [email protected]

谢谢了
2 楼 marssstone 2008-09-16  
是否要讲hbm.xml配置在hibernate.cfg.xml中
3 楼 marssstone 2008-09-16  
POJO类如果有SET和GET方法是否影响?
4 楼 jespring 2010-08-11  
太好了。要早点看到就好了。害得我配置了好多个pojo。谢谢
  相关解决方案