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 是 Hibernate 框架中的一种 callback 机制,允许开发者在持久层访问时执行自定义操作。HibernateCallback 是 Spring 框架中与 Hibernate 整合的重要组件,通过它可以实现灵活的持久层访问。 在 ...
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...
在某些情况下,我们需要在 Hibernate DAO 中执行原生 SQL 语句,这时我们可以使用 `HibernateCallback` 接口来实现该功能。 例如,我们可以使用以下代码来执行一个原生 SQL 语句: ```java public Object ...
### 泛型Hibernate的实现与Spring集成 #### 一、泛型Hibernate概念及其实现 在Java开发领域,尤其在企业级应用开发中,Hibernate框架因其强大的对象关系映射(ORM)能力而受到广泛欢迎。泛型Hibernate是利用Java...
Spring提供了org.springframework.orm.hibernate3.HibernateTemplate类和org.springframework.orm.hibernate3.HibernateCallback接口来方便和Hibernate整合。 HibernateTemplate类封装了Hibernate的主要类,它提供了...
6. **Callback机制**:通过HibernateCallback接口,可以在Hibernate Session内部执行自定义操作,保持事务的一致性。 **三、使用示例** 在使用HibernateTemplate之前,需要配置SessionFactory,并将其注入到...
本文详细介绍了Spring与Hibernate集成的过程,包括如何配置`SessionFactory`、使用`HibernateTemplate`简化数据操作、通过`HibernateDaoSupport`提高代码可维护性以及利用`HibernateCallback`实现更复杂的业务逻辑。...
通过`getHibernateTemplate().executeFind()`方法,我们创建了一个`HibernateCallback`回调,内部执行SQL查询。这里使用了HQL(Hibernate Query Language)编写查询语句,`"from ControlScreen order by id desc"`...
HibernateCallBack接口允许开发者在Hibernate操作的前后插入自定义的逻辑。通过实现这个接口,可以在执行特定数据库操作前后的回调函数中进行额外的工作,如事务控制、日志记录等。 6.5.6 使用IoC容器组装各种组件 ...
这是一个核心方法,它接受一个HibernateCallback接口的实例作为参数,允许在事务上下文中执行自定义的数据库操作。`execute`方法会确保在事务中执行回调方法,这样可以保证数据库操作的原子性。`exposeNativeSession...
它们可以通过继承Hibernate的`Serializable`接口或实现`HibernateCallback`接口来实现持久化。 5. **Session接口**:Session是Hibernate的主要工作单元,负责对象的持久化操作,如保存、更新、删除和查询。它是线程...
`queryForPage` 方法通过`getHibernateTemplate().executeFind()`方法执行HQL查询,并利用`HibernateCallback`接口回调来设置查询的起始位置和最大结果数,从而实现分页。`getAllRowCount` 方法则直接返回HQL查询后...
它通过回调机制(HibernateCallback)对Hibernate的操作进行封装,使开发者能够以一种更面向对象的方式处理数据库交互。例如,你可以通过实现HibernateCallback接口的doInHibernate方法,传入一个回调函数,执行特定...
此外,Spring还提供了HibernateTemplate和HibernateCallback接口,使得事务管理变得更加简单。在`applicationContext.xml`中,我们需要配置Hibernate的相关bean,如SessionFactory、DataSource等。 对于Struts和...
3. **模板方法模式**:Spring 为 Hibernate 提供了三种主要的支持方式:`HibernateDaoSupport`、`HibernateTemplate` 和 `HibernateCallback` 接口。其中,`HibernateTemplate` 是一个非常实用的工具类,它可以简化 ...
Spring还支持使用回调机制(如HibernateCallback)处理特殊查询和分页。 Hibernate的核心在于对象关系映射,它允许我们将Java对象直接映射到数据库表。开发者需要正确配置实体类(Entity)和数据访问对象(DAO),...
值得注意的是,Hibernate 4.1.6版本不再包含`HibernateTemplate`、`HibernateCallback`以及`HibernateDaoSupport`等类。这些类在旧版本中用于简化数据库操作,但在新版本中,开发者需要进行相应的替换。例如,可以...
此外,`HibernateTemplate`还支持`HibernateCallback`接口,允许开发者在回调方法`doInHibernate(Session session)`中使用原生的Hibernate API,以应对更复杂的数据访问需求。这种方法确保了灵活性,即使在Spring的...
return this.getHibernateTemplate().executeFind(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException, SQLException { Query query = session.createQuery(...
虽然`HibernateTemplate`提供了很多便利,但它在处理复杂查询时可能需要创建内部类(inner class),如在分页查询时使用`execute(HibernateCallBack)`,这可能会增加调试的复杂性。相比之下,直接使用`Session`进行...