`
Callan
  • 浏览: 731528 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

使用hibernate SQLQuery实现动态表

    博客分类:
  • Java
阅读更多
我在实际的项目应用中,有时会设计出这样的一种数据表,每个时间段产生一个新表,例如是按年或月或日。相同类型的表中,所有的字段结构都是一样的。而 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 写到配置文件中,根据不同的数据库,装载相应的配置文件咯。

5
0
分享到:
评论
5 楼 z6978445 2015-02-10  
查询呢?比如要查出 tblRead200710 表与 tblRead200711 表的数据,并且支持分页显示???
4 楼 jespring 2010-08-11  
太好了。要早点看到就好了。害得我配置了好多个pojo。谢谢
3 楼 marssstone 2008-09-16  
POJO类如果有SET和GET方法是否影响?
2 楼 marssstone 2008-09-16  
是否要讲hbm.xml配置在hibernate.cfg.xml中
1 楼 marssstone 2008-09-16  
楼主能否发份代码,感激不尽

邮箱 harryyang1986@sina.com

谢谢了

相关推荐

    Hibernate SQLQuery执行原生SQL.docx

    通过Session接口,我们能够很方便的创建一个SQLQuery(SQLQuery是一个接口,在Hibernate4.2.2之前,默认返回的是SQLQuery的实现类——SQLQueryImpl对象,在下文中出现的SQLQuery如非注明,都是指该子类)对象来进行...

    Hibernate中的query 分页.doc

    query.setFirstResult()是数据库SQL语句实现。 2.你说是在数据库就分页好呢?还是把结果集都取到内存再分页好呢?(应该是在数据库就分了好些吧,但是如果在内存分页的话,换页的时候是不是更快一些呢?) 3.在...

    Hibernate+中文文档

    16.1. 使用SQLQuery 16.1.1. 标量查询(Scalar queries) 16.1.2. 实体查询(Entity queries) 16.1.3. 处理关联和集合类(Handling associations and collections) 16.1.4. 返回多个实体(Returning multiple ...

    hibernate3.2中文文档(chm格式)

    16.1. 使用SQLQuery 16.1.1. 标量查询(Scalar queries) 16.1.2. 实体查询(Entity queries) 16.1.3. 处理关联和集合类(Handling associations and collections) 16.1.4. 返回多个实体(Returning multiple ...

    HibernateAPI中文版.chm

    16.1. 使用SQLQuery 16.1.1. 标量查询(Scalar queries) 16.1.2. 实体查询(Entity queries) 16.1.3. 处理关联和集合类(Handling associations and collections) 16.1.4. 返回多个实体(Returning multiple ...

    最全Hibernate 参考文档

    9.1.4. 混合使用“每个类分层结构一张表”和“每个子类一张表” 9.1.5. 每个具体类一张表(Table per concrete class) 9.1.6. Table per concrete class, using implicit polymorphism 9.1.7. 隐式多态和其他继承映射...

    Hibernate 中文 html 帮助文档

    16.1. 使用SQLQuery 16.1.1. 标量查询(Scalar queries) 16.1.2. 实体查询(Entity queries) 16.1.3. 处理关联和集合类(Handling associations and collections) 16.1.4. 返回多个实体(Returning multiple entities)...

    Hibernate中文详细学习文档

    16.1. 使用SQLQuery 16.1.1. 标量查询(Scalar queries) 16.1.2. 实体查询(Entity queries) 16.1.3. 处理关联和集合类(Handling associations and collections) 16.1.4. 返回多个实体(Returning multiple ...

    Hibernate注释大全收藏

    Hibernate 使用 SQL Union 查询来实现这种策略。 这种策略支持双向的一对多关联,但不支持 IDENTIFY 生成器策略,因为ID必须在多个表间共享。一旦使用就不能使用AUTO和IDENTIFY生成器。 每个类层次结构一张表 @...

    Hibernate_3.2.0_符合Java习惯的关系数据库持久化

    16.1. 使用SQLQuery 16.1.1. 标量查询(Scalar queries) 16.1.2. 实体查询(Entity queries) 16.1.3. 处理关联和集合类(Handling associations and collections) 16.1.4. 返回多个实体(Returning multiple ...

    hibernate 体系结构与配置 参考文档(html)

    使用SQLQuery 16.2. 别名和属性引用 16.3. 命名SQL查询 16.3.1. 使用return-property来明确地指定字段/别名 16.3.2. 使用存储过程来查询 16.3.2.1. 使用存储过程的规则和限制 16.4. 定制SQL用来create,...

    hibernate 教程

    Hibernate查询语言(Query Language), 即HQL 11.1. 大小写敏感性(Case Sensitivity) 11.2. from 子句 11.3. 联合(Associations)和连接(joins) 11.4. select子句 11.5. 统计函数(Aggregate ...

    Hibernate教程

    10.1.4. 混合使用“每个类分层结构一张表”和“每个子类一张表” 10.1.5. 每个具体类一张表(Table per concrete class) 10.1.6. Table per concrete class, using implicit polymorphism 10.1.7. 隐式多态和其他...

    Hibernate_二级缓存总结

    它可以使用不同的缓存实现,如 EhCache 、 JBossCache 、 OsCache 等 (二级缓存是缓存实体对象的) 还有一个类型的 CACHE 就是 QueryCache . 它的作用就是缓存一个 Query 以及 Query 返回对象的 Identifier 以及...

    Hibernate3+中文参考文档

    9.1.4. 混合使用“每个类分层结构一张表”和“每个子类一张表” 9.1.5. 每个具体类一张表(Table per concrete class) 9.1.6. Table per concrete class, using implicit polymorphism 9.1.7. 隐式多态和其他继承映射...

    hibernate3.04中文文档.chm

    10.1.4. 混合使用“每个类分层结构一张表”和“每个子类一张表” 10.1.5. 每个具体类一张表(Table per concrete class) 10.1.6. Table per concrete class, using implicit polymorphism 10.1.7. 隐式多态和其他...

    Hibernate参考文档

    16.1. 使用SQLQuery 16.1.1. 标量查询(Scalar queries) 16.1.2. 实体查询(Entity queries) 16.1.3. 处理关联和集合类(Handling associations and collections) 16.1.4. 返回多个实体(Returning multiple entities)...

    hibernate 框架详解

    创建一个基于SQL的Query 17.2. 别名和属性引用 17.3. 命名SQL查询 17.3.1. 使用return-property来明确地指定字段/别名 17.3.2. 使用存储过程来查询 17.3.2.1. 使用存储过程的规则和限制 17.4. 定制SQL用来...

    hibernate总结

    2. 通过HQL/SQL 检索 hibernate query language (面向对象的查询语言) * a) 不再操纵表,它操纵的是持久化类的对象 b) 面向对象的 3. QBC ( query by criteria ) 更加面向对象 4. QBE ( query by Example ) 5....

    hibernate

    Hibernate查询语言(Query Language), 即HQL 11.1. 大小写敏感性(Case Sensitivity) 11.2. from 子句 11.3. 联合(Associations)和连接(joins) 11.4. select子句 11.5. 统计函数(Aggregate ...

Global site tag (gtag.js) - Google Analytics