使用Hibernate SQLquery实现动态表

在实际的项目应用中,有时会设计出这样的一种数据表,每个时间段产生一个新表,例如是按年或月或日。相同类型的表中,所有的字段结构都是一样的。而 Hibernate 提供的类与表的映射,是只能映射到一个具体表的,在程序的运行过程中,很难去动态修改一个 hbm 对应的表名。我在网上也有看到一实现,但是很复杂,并且不符合我的要求。

创新互联是一家从事企业网站建设、成都网站设计、网站制作、行业门户网站建设、网页设计制作的专业网络公司,拥有经验丰富的网站建设工程师和网页设计人员,具备各种规模与类型网站建设的实力,在网站建设领域树立了自己独特的设计风格。自公司成立以来曾独立设计制作的站点近千家。

因此我就想到直接用 jdbc 去操作数据库,这样的做法是绕过 Hibernate 了。方法是从 Hibernate 的 session 中,直接取得数据库 connection ,然后就直接 jdbc 了。

后来在升级了 proxool 到 9.0RC3 后,发现居然出现了数据库连接无法释放的问题。为了解决这个问题,我查阅了 Hibernate doc。我发现原来用Hibernate 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 的片段是

 
 
 
  1. < class name= "ReadInfo" table= "tblReadInfo " mutable = "false" >   
  2.         < composite-id>   
  3.             < key-property name= "userId" column= "userId" type= "integer" / >   
  4.             < key-property name= "year" column= "year" type= "integer" / >   
  5.             < key-property name= "month" column= "month" type= "integer" / >   
  6.             < key-property name= "day" column= "day" type= "integer" / >   
  7.         < / composite-id>   
  8.         < property name= "point" column= "point" type= "integer" / >   
  9.     < / class>  

上面的xml,注意 2 个细节

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

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

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

 
 
 
  1. public ReadInfo selectReadInfo( Integer userId, Integer year,   
  2.             Integer month, Integer day) throws HibernateException  
  3.     {   
  4.          ReadInfo readInfo = null ;   
  5.  
  6.          Session session = getSession ( ) ;   
  7.         Transaction tx = session. beginTransaction( ) ;   
  8.  
  9.         try   
  10.         {   
  11.             String sql = "select * from tblRead"   
  12.                 + Misc. formatMoon( year, month)   
  13.                 + " where userId=? and day=?" ;   
  14.  
  15.              SQLQuery query = session. createSQLQuery( sql ) ;   
  16.             query . addEntity( ReadInfo. class ) ;   
  17.  
  18.             query . setLong ( 0, userId) ;   
  19.             query . setInteger( 1, day) ;   
  20.  
  21.              readInfo = ( ReadInfo) query . uniqueResult( ) ;   
  22.  
  23.              tx. commit ( ) ;   
  24.         }   
  25.         catch ( HibernateException e)   
  26.         {   
  27.             log . error ( "catch exception:" , e) ;   
  28.  
  29.             if ( tx ! = null )   
  30.             {   
  31.                  tx. rollback ( ) ;   
  32.             }   
  33.  
  34.             throw e;   
  35.         }   
  36.         return readInfo;   
  37.     }  

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

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

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

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

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

再看一个 insert 操作

 
 
 
  1. public void insertReadInfo( ReadInfo readInfo) throws HibernateException  
  2.     {   
  3.          Session session = getSession ( ) ;   
  4.         Transaction tx = session. beginTransaction( ) ;   
  5.  
  6.         try   
  7.         {   
  8.             String sql = "insert into tblRead"   
  9.                 + Misc. formatMoon( readInfo. getYear ( ) , readInfo. getMonth ( ) )   
  10.                 + " (userId, year, month, day, point) values (?, ?, ?, ?, ?)" ;   
  11.  
  12.              SQLQuery query = session. createSQLQuery( sql ) ;   
  13.  
  14.             query . setLong ( 0, readInfo. getUserId( ) ) ;   
  15.             query . setInteger( 1, readInfo. getYear ( ) ) ;   
  16.             query . setInteger( 2, readInfo. getMonth ( ) ) ;   
  17.             query . setInteger( 3, readInfo. getDay ( ) ) ;   
  18.             query . setInteger( 4, readInfo. getPoint ( ) ) ;   
  19.  
  20.             query . executeUpdate ( ) ;   
  21.  
  22.              tx. commit ( ) ;   
  23.         }   
  24.         catch ( HibernateException e)   
  25.         {   
  26.             log . error ( "catch exception:" , e) ;   
  27.  
  28.             if ( tx ! = null )   
  29.             {   
  30.                  tx. rollback ( ) ;   
  31.             }   
  32.  
  33.             throw e;   
  34.         }   
  35.     }  

同理,update, delete 等操作也是这样通过Hibernate SQLquery来实现的。

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

【编辑推荐】

  1. Hibernate更新出错的解决
  2. 深入浅出Hibernate学习笔记 Criteria Query
  3. 正确理解Hibernate Inverse
  4. 对Hibernate缓存机制的分析
  5. Hibernate HQL查询解析

网页名称:使用Hibernate SQLquery实现动态表
标题路径:http://www.mswzjz.cn/qtweb/news47/99547.html

攀枝花网站建设、攀枝花网站运维推广公司-贝锐智能,是专注品牌与效果的网络营销公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 贝锐智能