`

Hibernate_HibernateCallback

 
阅读更多

HibernateTemplate还提供一种更加灵活的方式来操作数据库,通过这种方式可以完全使用Hibernate的操作方式。HibernateTemplate的灵活访问方式是通过如下两个方法完成:

Object execute(HibernateCallback action)

List execute(HibernateCallback action)

这两个方法都需要一个HibernateCallback的实例,HibernateCallback实例可在任何有效的Hibernate数据访问中使用。程序开发者通过HibernateCallback,可以完全使用Hibernate灵活的方式来访问数据库,解决Spring封装Hibernate后灵活性不足的缺陷。HibernateCallback是一个接口,该接口只有一个方法doInHibernate(org.hibernate.Session session),该方法只有一个参数Session。在开发中提供HibernateCallback实现类时,必须实现接口里包含的 doInHibernate方法,在该方法体内即可获得Hibernate Session的引用,一旦获得了Hibernate Session的引用,就可以完全以Hibernate的方式进行数据库访问。

注意:方法doInHibernate方法内可以访问Session,该Session对象是绑定到该线程的Session实例。该方法内的持久层操作,与不使用Spring时的持久层操作完全相同。这保证对于复杂的持久层访问,依然可以使用Hibernate的访问方式。

 

通常,程序中采用实现HibernateCallback的匿名内部类来获取HibernateCallback的实例,方法doInHibernate的方法体就是Spring执行的持久化操作。具体代码如下:

 

public class PersonDaoImpl implements PersonDao

{

 private SessionFactory sessionFactory;

 public void setSessionFactory(SessionFactory sessionFactory){

  this.sessionFactory = sessionFactory;

 }

 /**

  * 

  * 通过人名查找所有匹配该名的Person实例

  * 

  * @param name

  *            匹配的人名

  * 

  * @return 匹配该任命的全部Person集合

  * 

  */

 public List findPersonsByName(final String name){

  HibernateTemplate hibernateTemplate =new HibernateTemplate(this.sessionFactory); // 创建HibernateTemplate实例

  return (List) hibernateTemplate.execute( // 返回HibernateTemplate的execute的结果

    // 创建匿名内部类

    new HibernateCallback(){

     public Object doInHibernate(Session session) throws HibernateException{

      List result = session.createCriteria(Person.class).add(Restrictions.like("name", name+"%").list();

      return result;

     }

    });

    }

}

 

 

---------------------------------------------------------------

Spring 对 hibernate 的集成(使用回调callback)

 

比如在删除一条在数据库操作的时候 我们一般是类似是这样使用:

this.getHibernateTemplate().delete("from Information where INFOID='"+infoid.trim()+"'");

 

然而具体在spring内部是怎么操作的呢?

delete()----->excecute()----->执行回调方法HibernateCallback .doInHibernate()。

 

下面来让我们来直接看一下spring的源代码。

//hibernate回调接口

public interface HibernateCallback {

Object doInHibernate(Session session) throws HibernateException, SQLException;

}

//...

 

package org.springframework.orm.hibernate;

public class HibernateTemplate extends HibernateAccessor implements HibernateOperations {

//...

 

public int delete(final String queryString) throws DataAccessException {

  Integer deleteCount = (Integer) execute(new HibernateCallback() {//定义回调实现

   public Object doInHibernate(Session session) throws HibernateException {

    checkWriteOperationAllowed(session);

    return new Integer(session.delete(queryString));//此处有hibernate的实现操作

   }

  });

  return deleteCount.intValue();

 }

 

 public Object execute(HibernateCallback action) throws DataAccessException {

  Session session = (!isAllowCreate() ? SessionFactoryUtils.getSession(getSessionFactory(), false) :

  SessionFactoryUtils.getSession(getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator()));

  boolean existingTransaction = TransactionSynchronizationManager.hasResource(getSessionFactory());

  if (!existingTransaction && getFlushMode() == FLUSH_NEVER) {

   session.setFlushMode(FlushMode.NEVER);

  }

  try {

   Object result = action.doInHibernate(session);//此处调用hibernatecallback回调接口即hibernate的实现

   flushIfNecessary(session, existingTransaction);

   return result;

  }

  catch (HibernateException ex) {

   throw convertHibernateAccessException(ex);

  }

  catch (SQLException ex) {

   throw convertJdbcAccessException(ex);

  }

  catch (RuntimeException ex) {

   // callback code threw application exception

   throw ex;

  }

  finally {

   SessionFactoryUtils.closeSessionIfNecessary(session, getSessionFactory());

  }

 }

 

//...

 

//其他操作类似

}

 

--------------------------------------------------------

Hibernate中运用doInHibernate 构造公用findByhql和updateByHql方法

 

在hibernate中,运用doInHibernate,避免了手动open session和close session ,减少了一系列session关闭的麻烦。

 

公用的setParameter 方法,下面有调用,传入一个query 实例,和Map<String, Object> map 类型的参数

private void setParameter(Query query, Map<String, Object> map) {

  if (map != null && !map.isEmpty()) {

   Set<String> keySet = map.keySet();

   for (String string : keySet) {

    Object obj = map.get(string);

    // 这里考虑传入的参数是什么类型,不同类型使用的方法不同

    if (obj instanceof Collection<?>) {

     query.setParameterList(string, (Collection<?>) obj);

    } else if (obj instanceof Object[]) {

     query.setParameterList(string, (Object[]) obj);

    } else {

     query.setParameter(string, obj);

    }

   }

  }

 }

 

 

public void updateByHql(final String hql, final Map<String, Object> map) throws Exception {

  template.execute(new HibernateCallback() {

      @Override

      public Object doInHibernate(Session session) throws HibernateException, SQLException {

         Query query = session.createQuery(hql);

         setParameter(query, map); //调用set参数的方法

         query.executeUpdate();

         return null;

         }

      });

    }

 

public List<Object> findByHql(final String hql, final Map<String, Object> map) throws Exception {

  return (List<Object>) template.execute(new HibernateCallback() {

   public List<Object> doInHibernate(final Session session) throws HibernateException, SQLException {

    Query query = session.createQuery(hql);

    setParameter(query, map);

    return query.list();

   }

  });

}

 

 

调用例子:

String hql = "from ABC where bb = :aa";

  Map<String, Object> map = new HashMap<String, Object>();

  map.put("aa", 22);

  List<Object> cList = commonDao.findByHql(hql, map);

  if (cList == null || cList.size() == 0)

   return null;

  else

   return (ABC) cList.get(0);

 

update类似与query,只是没有返回参数

 

 

 

--------------------------------------------------------

下面的代码对HibernateDaoSupport类进行扩展(虽然Spring 2.0的HibernateTemplate提供了一个分页方法setMaxResults,但仅此一个方法依然不能实现分页查询),这种扩展主要是为该类增加了3个分页查询的方法,分页查询时必须直接调用Hibernate的Session完成,因此,必须借助于HibernateCallBack的帮助。

public class YeekuHibernateDaoSupport extends HibernateDaoSupport

{

    /**

     * 使用hql 语句进行分页查询操作

     * @param hql 需要查询的hql语句

     * @param offset 第一条记录索引

     * @param pageSize 每页需要显示的记录数

     * @return 当前页的所有记录

     */

    public List findByPage(final String hql, final int offset, final int pageSize)

    {

        //HibernateDaoSupport已经包含了getHibernateTemplate()方法

        List list = getHibernateTemplate().executeFind(new

        HibernateCallback()

            {

                public Object doInHibernate(Session session) throws HibernateException, SQLException

                //该方法体内以Hibernate方法进行持久层访问

                {

                    List result = session.createQuery(hql) .setFirstResult(offset) .setMaxResults(pageSize) .list();

                    return result;

                }

            });

        return list;

    }

    /**

     * 使用hql 语句进行分页查询操作

     * @param hql 需要查询的hql语句

     * @param value 如果hql有一个参数需要传入,value就是传入的参数

     * @param offset 第一条记录索引

     * @param pageSize 每页需要显示的记录数

     * @return 当前页的所有记录

     */

    public List findByPage(final String hql , final Object value , final int offset, final int pageSize)

    {

        List list = getHibernateTemplate().executeFind(new

        HibernateCallback()

            {

                public Object doInHibernate(Session session) throws HibernateException, SQLException

                {

                    //下面查询的是最简单的Hiberante HQL查询

                    List result = session.createQuery(hql) .setParameter(0, value) .setFirstResult(offset) .setMaxResults(pageSize) .list();

                    return result;

                }

            });

        return list;

    }

    /**

     * 使用hql 语句进行分页查询操作

     * @param hql 需要查询的hql语句

     * @param values 如果hql有多个参数需要传入,values就是传入的参数数组

     * @param offset 第一条记录索引

     * @param pageSize 每页需要显示的记录数

     * @return 当前页的所有记录

     */

    public List findByPage(final String hql, final Object[] values, final int offset, final int pageSize)

    {

        List list = getHibernateTemplate().executeFind(new

        HibernateCallback()

            {

                public Object doInHibernate(Session session) throws HibernateException, SQLException

                {

                    Query query = session.createQuery(hql);

                    for (int i = 0 ; i < values.length ; i++)

                    {

                        query.setParameter( i, values[i]);

                    }

                    List result = query.setFirstResult(offset) .setMaxResults(pageSize) .list();

                    return result;

                }

            });

        return list;

    }

}

在上面的代码实现中,直接使用了getHibernateTemplate()方法,这个方法由Hibernate- DaoSupport提供。而YeekuHibernateDaoSupport是HibernateDaoSupport的子类,因此,可以直接使用该方法。

当实现doInHibernate(Session session)方法时,完全以Hibernate的方式进行数据库访问,这样保证了Hibernate进行数据库访问的灵活性。

注意:Spring提供的XxxTemplate和XxxCallBack互为补充,二者体现了Spring框架设计的用心良苦:XxxTemplate对通用操作进行封装,而XxxCallBack解决了封装后灵活性不足的缺陷。

 

 

--------------------------------------------------------

Spring和Hibernate集成的HibernateTemplate的一些常用方法总结

 

1:get/load存取单条数据

public Teacher getTeacherById(Long id) {  

    return (Teacher)this.hibernateTemplate.get(Teacher.class, id);  

}  

public Teacher getTeacherById(Long id) {  

    return (Teacher)this.hibernateTemplate.load(Teacher.class, id);  

}  

 

2:find/iterate查询操作

public Iterator getTeachersByAge(int age) {  

    Iterator iterator = null;  

      

    //使用find方法  

    List list = (List)this.hibernateTemplate().find("from Teacher t where t.age>?", new Integer(age));  

    iterator = list.iterator();  

      

    //使用iterator方法  

    iterator = this.hibernateTemplate().iterate("from Teacher t where t.age>?", new Integer(age));  

      

    return iterator;  

}  

find和iterato的区别主要是iterate采用了N+1次查询,对于大批量查询,比如查询10000条记录,那么iterate就要执行10000+1次查询,find和iterate应根据具体的实际

情况来使用,对于频繁的写操作对象,应使用find查询,而对于一些只读的数据对象,应使用iterate操作,因为iterate操作使用了Hibernate的缓存机制

 

3:save/update/saveOrUpdate/delete 保存/更新/删除操作  

public void save(Teacher teacher) {  

    this.hibernateTemplate.save(teacher);  

}  

public void update(Teacher teacher) {  

    this.hibernateTemplate.update(teacher);  

}  

public void update(Teacher teacher) {  

    this.hibernateTemplate.saveOrUpdate(teacher);  

}  

public void update(Teacher teacher) {  

    this.hibernateTemplate.delete(teacher);  

}  

 

4:bulkUpdate批量删除或者更新

bulkUpdate提供了批量删除和更新,直接转换为相应的update/delete SQL进行批量删除和更新

public void batchDelete(String name, int age) {  

    this.hibernateTemplate.bulkUpdate("delete Teacher where name=? and age = ?", new Object[]{name, age});  

}  

public void batchUpdate(String name, String newName) {  

    this.hibernateTemplate.bulkUpdate("update Teacher set name=? where name=?", new Object[]{newName, name});  

}  

此时要注意的一个问题是,使用bulkUpdate操作,必须手工清除相关对象在Hibernate中的缓存(包括一级缓存和二级缓存)

 

5:execute核心方法

public Object execute(HibernateCallBack action, boolean exposeNativeSession) throws DataAccessException {  

        Session session = getSession();  //获取一个Session  

        boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getSessionFactory());  //当前session是否在事务中  

        FlushMode previousFlushMode = null;  

        try {  

            previousFlushMode = applyFlushMode(session, existingTransaction); //应用flush模式  

            enableFilters(session);  

              

            Session sessionToExpose = (exposeNativeSession? session: createSessionProxy(session));  //暴露给action的session  

            Object result = action.doInHibernate(sessionToExpose);  //执行action  

            flushIfNecessary(session, existingTransaction);  

            return result;  

              

        } catch(HibernateException ex) {  

            throw convertHibernateAccessException(ex);  

        } catch(SQLException ex) {  

            throw convertJdbcAccessException(ex);  

        } catch(RuntimeException ex) {  

            throw ex;  

        } finally {  

            if(existingTransaction) {  //如果session在事务中,则不关闭session  

                disableFilters(session);  

                if(previousFlushMode != null) {  

                    session.setFlushMode(previousFlushMode);  

                }  

            } else {  

                SessionFactoryUtils.releaseSession(session, getSessionFactory());  //释放session  

            }  

        }  

    }  

*HibernateCallBack,一般用来实现特定的业务逻辑

*exposeNativeSession:是一个布尔值,要暴露给HibernateCallBack实际的session对象,而不是一个代理过的对象

 

6:一般情况下,只有HIberateTemplate提供的方法不能满足要求时才使用execute方法,它的使用情况如下所示,

public void createDatabaseSchema() throws DataAccessException {  

    HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);  

    //调用HibernateTempalte的execute方法  

    hibernateTemplate.execute(new HibernateCallback() {  

        public Object doInHibernate(Session session) throws HibernateException, SQLException {  //实现HibernateCallback的doInHibernate方法  

            //具体实现  

            Connection conn = session.connection();  

            final Dialect dialect = Dialect.getDialect(configuration.getProperties);  

            String[] sql = configuration.generateSchemaCreationScript(dialect);  

            executeSchemaScript(conn, sql);  

        }  

    });  

}  

使用execute方法的重点是实现HibernateCallback的doInHibernate方法,它会传递一个Session实例,可以使用此Session实例操作数据库,由此看出execute方法的好处是应用程序不用关心session的创建和释放,只需要处理关心的业务逻辑即可。

 

--------------------------------------------------------

 

ref: 

http://www.blogjava.net/rain1102/articles/170638.html

http://blog.csdn.net/changewang/article/details/575191

http://yunqiang-zhang-hotmail-com.iteye.com/blog/1973010

http://www.linuxidc.com/Linux/2011-12/48719.htm

 

分享到:
评论

相关推荐

    HibernateCallback使用方法

    HibernateCallback使用方法

    Hibernate3.6.10用到的jiar

    Hibernate3.6.10用到的jiar antlr-2.7.6.jar,commons-collections-3.1, commons-logging-1.1.3, dom4j-1.6.1, ejb3-persistence, hibernate-jpa-2.0-api-1.0.1.Final, hibernate3, javassist-3.12.0.GA, jta...

    第24次课-1 Spring与Hibernate的整合

    Spring提供了org.springframework.orm.hibernate3.HibernateTemplate类和org.springframework.orm.hibernate3.HibernateCallback接口来方便和Hibernate整合。 HibernateTemplate类封装了Hibernate的主要类,它提供了...

    Spring整合Hibernate 详解.doc

    6.5 Spring整合Hibernate 6.6 Spring提供的DAO支持 6.5.2 管理Hibernate的...6.5.4 使用HibernateCallBack 6.5.6 使用IoC容器组装各种组件 6.5.7启动web容器读取xml配置文件 6.5.8了解继承自HibernateDaoSupport类DAO

    ssh(structs,spring,hibernate)框架中的上传下载

    HibernateDaoSupport封装了HibernateTemplate,而HibernateTemplate封装了Hibernate所提供几乎所有的的数据操作方法,如execute(HibernateCallback action),load(Class entityClass, Serializable id),save(final ...

    spring_MVC源码

    文中用的框架版本:spring 3,hibernate 3,没有的,自己上网下。 先说web.xml配置: [java] view plaincopy 01.&lt;?xml version="1.0" encoding="UTF-8"?&gt; 02....

    HibernateTemplate详细描述以及使用范围

    对Spring框架中,HibernateTemplate的使用,底层dao中HibernateTemplate的使用以及HibernateCallBack调用等等

    新闻发布系统

    return template.execute(new HibernateCallback&lt;List&lt;News&gt;&gt;() { public List&lt;News&gt; doInHibernate(Session session) throws HibernateException,SQLException { List&lt;News&gt; list = null; Query query...

    SPRING API 2.0.CHM

    HibernateInterceptor HibernateInterceptor HibernateJdbcException HibernateJdbcException HibernateJpaDialect HibernateJpaVendorAdapter HibernateObjectRetrievalFailureException ...

Global site tag (gtag.js) - Google Analytics