hibernate调用jdbc接口

在 Hibernate 框架中提供操作 JDBC 的接口的解决方案

Hibernate 的 session 机制

我们知道 Hibernate 框架本身也是建立在 JDBC 之上的数据持久层实现,因此,要在框架本身提供操作 JDBC 的接口,需要切入其对 JDBC 封装的细节。

通过研究和查阅 Hibernate 的框架源代码及参考文档,我们发现,Hibernate 的 Session 会话是进行持久化的基础,所有的持久化操作都是在 Session 的基础上进行的,在实现上它是和 JDBC 中的 connection 数据库连接绑定的,也就是说,Hibernate 的会话域基于一个实际的 connection 类实例,二者之间的关系如下图所示:


图 2. Hibernate Session 机制示意图

由上可以看到,Hibernate 中的 session 是单线程的,代表了一次会话的过程。实际上是把一个 JDBC Connection 打包了,每一个 Session 实例和一个数据库事务绑定。其生命周期是与与之关联的 connection 实例的生命周期一致的。

具体解决方案

由上面的 Hibernate 的 Session 机制我们意识到,只要能获取到 Hibernate 当前会话中的 Connection,则获得了 JDBC 的底层数据库连接实例,剩下就都是 JDBC 的范畴了。再查阅 Hibernate 的 API,发现 HibernateTemplate 类中 SessionFactory 成员的 getCurrentSession() 方法即可获得 Hibernate 环境下的当前活动的 Session 会话,而 Hibernate 中 Session 实例的 connection() 方法即可获得该会话中绑定的 Connection 数据库连接实例。

问题迎刃而解了,既然可以操作 Connection 实例,那与之关联的 Statement、ResultSet 等基本 JDBC 类均在我们控制范围中了,我们采用接口模式设计一个轻量级解决方案,使其在保持原 Hibernate 的增删改操作方式前提下灵活提供操作 JDBC 的接口。设计类图如下图所示:


图 3. 解决方案设计类示意图

设计中,AbstractHibernateDao 类作为 DAO 操作的基本类,保留原有 Hibenrate 框架下的新增,修改,删除等 API。BaseHibernateDao 类继承 AbstractHibernateDao 类,在此类中增加了直接操作 JDBC 的接口。设计 getConnection 方法获取 JDBC 的数据库连接实例,设计 getObjectsBySql 方法作为对外的主要接口,该方法调用 fetchObjects 方法,这是具体的数据库记录到领域对象的转换操作,需要使用者 override 该方法以完成自有领域对象的填充细节。

实际实现的类代码如下所示:


清单 6. 解决方案实现代码

                              

AbstractHibernateDao.java:

abstract public class AbstractHibernateDao extends HibernateDaoSupport {

 

    protected Log logger = LogFactory.getLog(getClass());

    protected Class entityClass;

 

    protected Class getEntityClass() {

        return entityClass;

    }

 

    public List getAll() {

        return getHibernateTemplate().loadAll(getEntityClass());

    }

 

    public void save(Object o) {

        getHibernateTemplate().saveOrUpdate(o);

    }

 

    public void removeById(Serializable id) {

        remove(get(id));

    }

 

    public void remove(Object o) {

        getHibernateTemplate().delete(o);

    }

 

}

 

BaseHibernateDao.java:

abstract public class BaseHibernateDao extends AbstractHibernateDao{

    public Connection getConnection()

    {

        try

        {

 

            Session curSeesion =null;

            Connection con =null;

            curSeesion = super.getHibernateTemplate().getSessionFactory()

                .getCurrentSession();

            con = curSeesion.connection();

            return con;

        }

        catch(Exception es)

        {

            System.out.println(es.getMessage());

            return null;

        }

 

    }

 

    public ArrayList<Object> fetchObjects(ResultSet rs)

    {

        ArrayList<Object> ret = new ArrayList<Object>();

        //example:

        //while(rs.next())

        //{

        //Object object = new Object();

        //rs.getString(1);

        //rs.getString(2);

        //ret.add(object);                          

        //}

        return ret;

    }

 

 

    public ArrayList<Object> getObjectsBySql(String pureSql)

    {

        Connection  con = curSeesion.connection();

        ps   =   con.prepareStatement(sqlbuf.toString());

        rs = ps.executeQuery();

        try

        {

            return this.fetchObjects(rs);    

                      

        }

        catch(Exception es)

        {

            System.out.println(es.getMessage());

            return null;

        }

        finally

        {

            try

            {

                ps.close();

                rs.close();

                con.close();

            }

            catch (SQLException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

                      

        }

    }

}

 

使用该解决方案时,只需要将代码包解压至项目源代码目录,在想要直接操作 JDBC 接口的 DAO 模块继承 BaseHibernateDao 类,然后重写 fetchObjects 方法填入从自身数据库表字段填充到领域对象的操作 , 即可轻松调用 getObjectsBySql 传入原生 SQL 语句,返回具体的领域对象实体集合,当然使用者也可以通过 getConnection 获得 JDBC 的 Connection 实例来进行自己需要的特定的 JDBC 底层操作。

仍然以上文中的 A、B、C 表为例,采用该解决方案完成 top10 取数的代码示例如下:


清单 7. 使用解决方案示例

                              

public class testDAO extends BaseHibernateDao{

 

    private String sqlQuery =  " select tab1.ID,tab1.sumCol+tab2.sumCol"+

        " from(select a.ID, count(b.ID) sumCol"+

        "      from A a left join B b on a.ID=b.ID"+

        "      GROUP BY a.ID)tab1, "+

        "     (select a.ID,count(c.ID) sumCol"+

        "      from A a left join C c on a.ID=c.ID"+

        "      GROUP BY a.ID)tab2"+

        " where tab1.ID=tab2.ID"+

        " order by tab1.sumCol+tab2.sumCol desc";

 

    @override

    public ArrayList<A> fetchObjects(ResultSet rs)

    {

        ArrayList<A> ret = new ArrayList<A>();

        int count=1;

        while(rs.next())

        {

            A a = new A();

            a.setId(rs.getLong(1));

            System.out.println("top"+(count++)+" amount:"+rs.getLong(2));

            ret.add(object);                        

        }

        return ret;

    }

 

}



解决方案验证

在实际 mySql 数据库环境中,以 A 表数据量 1000 条,B 表数据量 3W 多条,C 表数据量 2000 条情况下进行上文中提到的 top10 的操作,采用 Hibernate 的耗时和用 JDBC 接口解决方案的效率比较如下:


表 1. Hibernate 框架方式与 JDBC 接口方式效率比较 1:

 

Hibernate 框架方式

采用 JDBC 接口解决方案

查询耗时

1475ms

1096ms

排序耗时

1035ms

0ms

总计:

2110ms

1096ms

 

A 表数据量 2000 条,B 表数据量 6W,C 表数据量 4000 条情况下,采用 Hibernate 的耗时和用 JDBC 接口解决方案的效率比较:


表 2. Hibernate 框架方式与 JDBC 接口方式效率比较 2:

 

Hibernate 框架方式

采用 JDBC 接口解决方案

查询耗时

2836ms

1657ms

排序耗时

1568ms

0ms

总计:

4404ms

1657ms

 

由以上结果可以看出:在数据量递增的情况下,采用 Hibernate 方式下效率与库表数据呈线性增长,且排序的操作的效率也是一样,而直接采用 JDBC 接口解决方案下效率远远高于 Hibernate 方式,且在数据量增长的情况下耗时的增长速度处于合理的区间内。

posted on 2011-06-30 09:48  Z.Y  阅读(922)  评论(0编辑  收藏  举报

导航