6.5.4 使用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的访问方式。

下面的代码对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解决了封装后灵活性不足的缺陷。

6.5.5 实现DAO组件

为了实现DAO组件,Spring提供了大量的XxxDaoSupport类,这些DAO支持类对于实现DAO组件大有帮助,因为这些DAO支持类已经完成了大量基础性工作。

Spring为Hibernate的DAO提供了工具类HibernateDaoSupport。该类主要提供如下两个方法以方便DAO的实现:

● public final HibernateTemplate getHibernateTemplate()。

● public final void setSessionFactory(SessionFactory sessionFactory)。

其中,setSessionFactory方法可用于接收Spring的ApplicationContext的依赖注入,可接收配置在Spring的SessionFactory实例,getHibernateTemplate方法用于返回通过SessionFactory产生的HibernateTemplate实例,持久层访问依然通过HibernateTemplate实例完成。

下面实现的DAO组件继承了Spring提供的HibernateDaoSupport类,依然实现了PersonDao接口,其功能与前面提供的PersonDao实现类完全相同。其代码如下:

public class PersonDaoHibernate extends HibernateDaoSupport implements PersonDao

{

/**

* 加载人实例

* @param id 需要加载的Person实例的主键值

* @return 返回加载的Person实例

*/

public Person get(int id)

{

return (Person)getHibernateTemplate().get(Person.class, new
        Integer(id));

}

/**

* 保存人实例

* @param person 需要保存的Person实例

*/

public void save(Person person)

{

getHibernateTemplate().save(person);

}

/**

* 修改Person实例

* @param person 需要修改的Person实例

*/

public void update(Person person)

{

getHibernateTemplate().update(person);

}

/**

* 删除Person实例

* @param id 需要删除的Person的id

*/

public void delete(int id)

{

getHibernateTemplate().delete(getHibernateTemplate().
        get(Person.class, new Integer(id)));

}

/**

* 删除Person实例

* @param person 需要删除的Person实例

*/

public void delete(Person person)

{

getHibernateTemplate().delete(person);

}

/**

* 根据用户名查找Person

* @param name 用户名

* @return 用户名对应的全部用户

*/

public List findByPerson(String name)

{

return getHibernateTemplate().find("from Person p where p.name
        like ?" , name);

}

/**

* 返回全部的Person实例

* @return 全部的Person实例

*/

public List findAllPerson()

{

return getHibernateTemplate().find("from Person ");

}

}

上面的代码与前面的PersonDAOImpl对比会发现,代码量大大减少。事实上,DAO的实现依然借助于HibernateTemplate的模板访问方式,只是HibernateDaoSupport将依赖注入SessionFactory的工作已经完成,获取HibernateTemplate的工作也已完成。该DAO的配置必须依赖于SessionFactory,配置文件与前面部署DAO组件的方式完全相同,此处不再赘述。

在继承HibernateDaoSupport的DAO实现里,Hibernate Session的管理完全不需要打开代码,而由Spring来管理。Spring会根据实际的操作,采用“每次事务打开一次session”的策略,自动提高数据库访问的性能。

6.5.6 使用IoC容器组装各种组件

至此为止,J2EE应用所需要的各种组件都已经出现了,从MVC层的控制器组件,到业务逻辑组件,以及持久层的DAO组件,已经全部成功实现。应用程序代码并未将这些组件耦合在一起,代码中都是面向接口编程,因此必须利用Spring的IoC容器将他们组合在一起。

从用户角度来看,用户发出HTTP请求,当MVC框架的控制器组件拦截到用户请求时,将调用系统的业务逻辑组件,而业务逻辑组件则调用系统的DAO组件,而DAO组件则依赖于SessionFactory和DataSource等底层组件实现数据库访问。

从系统实现角度来看,IoC容器先创建SessionFactory和DataSource等底层组件,然后将这些底层组件注入给DAO组件,提供一个完整的DAO组件,并将此DAO组件注入给业务逻辑组件,从而提供一个完整的业务逻辑组件,而业务逻辑组件又被注入给控制器组件,控制器组件负责拦截用户请求,并将处理结果呈现给用户——这一系列的衔接都由Spring的IoC容器提供实现。

下面给出关于如何在容器中配置J2EE组件的大致模板,其模板代码如下:

<?xml version="1.0" encoding="GBK"?>

<!-- beans是Spring配置文件的根元素,并且指定了Schema信息 -->

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 定义数据源Bean,使用C3P0数据源实现 -->

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
    destroy-method="close">

<!-- 指定连接数据库的驱动 -->

<property name="driverClass" value="com.mysql.jdbc.Driver"/>

<!-- 指定连接数据库的URL -->

<property name="jdbcUrl" value="jdbc:mysql://localhost/j2ee"/>

<!-- 指定连接数据库的用户名 -->

<property name="user" value="root"/>

<!-- 指定连接数据库的密码 -->

<property name="password" value="32147"/>

<!-- 指定连接数据库连接池的最大连接数 -->

<property name="maxPoolSize" value="40"/>

<!-- 指定连接数据库连接池的最小连接数 -->

<property name="minPoolSize" value="1"/>

<!-- 指定连接数据库连接池的初始化连接数 -->

<property name="initialPoolSize" value="1"/>

<!-- 指定连接数据库连接池的连接最大空闲时间 -->

<property name="maxIdleTime" value="20"/>

</bean>

<!-- 定义Hibernate的SessionFactory Bean -->

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.
    LocalSessionFactoryBean">

<!-- 依赖注入数据源,注入的正是上文中定义的dataSource -->

<property name="dataSource" ref="dataSource"/>

<!-- mappingResources属性用来列出全部映射文件 -->

<property name="mappingResources">

<list>

<!-- 以下用来列出所有的PO映射文件 -->

<value>lee/Person.hbm.xml</value>

<!-- 此处还可列出更多的PO映射文件 -->

</list>

</property>

<!-- 定义Hibernate的SessionFactory属性 -->

<property name="hibernateProperties">

<props>

<!-- 指定Hibernate的连接方言 -->

<prop key="hibernate.dialect">org.hibernate.dialect.
                MySQLDialect</prop>

<!-- 指定启动应用时,是否根据Hibernate映射文件创建数据表 -->

<prop key="hibernate.hbm2ddl.auto">update</prop>

</props>

</property>

</bean>

<!-- 配置Person持久化类的DAO Bean -->

<bean id="personDao" class="lee.PersonDaoImpl">

<!-- 采用依赖注入来传入SessionFactory的引用 -->

<property name="sessionFactory" ref="sessionFactory"/>

</bean>

<!-- 下面能以相同的方式配置更多的持久化Bean -->

...

<bean id="myService" class="lee.MyServiceImp">

<!-- 注入业务逻辑组件所必需的DAO组件 -->

<property name="peronDdao" ref=" personDao "/>

<!-- 此处可采用依赖注入更多的DAO组件 -->

...

</bean>

<!-- 配置控制器Bean,设置起作用域为Request -->

<bean name="/login" class="lee.LoginAction" scope="request">

<!-- 依赖注入控制器所必需的业务逻辑组件 -->

<property name="myService" ref=" myService "/>

</bean>

</beans>

在上面的配置文件中,同时配置了控制器Bean、业务逻辑组件Bean、DAO组件Bean以及一些基础资源Bean。各组件的组织被解耦到配置文件中,而不是在代码层次的低级耦合。

当客户端的HTTP请求向/login.do发送请求时,将被容器中的lee.LoginAction拦截,LoginAction调用myService Bean,myService Bean则调用personDao等系列DAO组件,整个流程将系统中的各组件有机地组织在一起。

注意:在实际应用中,很少会将DAO组件、业务逻辑组件以及控制组件都配置在同一个文件中。而是在不同配置文件中,配置相同一组J2EE应用组件。

6.5.7 使用声明式事务

在上面的配置文件中,部署了控制器组件、业务逻辑组件、DAO组件,几乎可以形成一个完整的J2EE应用。但有一个小小的问题:事务控制。系统没有任何事务逻辑,没有事务逻辑的应用是不可想象的。

Spring提供了非常简洁的声明式事务控制,只需要在配置文件中增加事务控制片段,业务逻辑代码无须任何改变。Spring的声明式事务逻辑,甚至支持在不同事务策略之间切换。

配置Spring声明式事务时,通常推荐使用BeanNameAutoProxyCreator自动创建事务代理。通过这种自动事务代理的配置策略,增加业务逻辑组件,只需要在BeanNameAutoProxyCreator Bean配置中增加一行即可,从而避免了增量式配置。

在上面的配置模板文件中增加如下配置片段,系统的myService业务逻辑组件将变成事务代理Bean,从而为业务逻辑方法增加事务逻辑。

<!-- 配置Hibernate的局部事务管理器 -->

<!-- 使用HibernateTransactionManager类,该类是PlatformTransactionManager
    接口,针对采用Hibernate持久化连接的特定实现 -->

<bean id="transactionManager"

class="org.springframework.orm.hibernate3.
         HibernateTransactionManager">

<!-- HibernateTransactionManager Bean需要依赖注入一个SessionFactory
        bean的引用 -->

<property name="sessionFactory" ref="sessionFactory"/>

</bean>

<!-- 配置事务拦截器Bean -->

<bean id="transactionInterceptor"

class="org.springframework.transaction.interceptor.
        TransactionInterceptor">

<!-- 事务拦截器bean需要依赖注入一个事务管理器 -->

<property name="transactionManager" ref="transactionManager"/>

<property name="transactionAttributes">

<!-- 下面定义事务传播属性 -->

<props>

<prop key="insert*">PROPAGATION_REQUIRED</prop>

<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>

<prop key="*">PROPAGATION_REQUIRED</prop>

</props>

</property>

</bean>

<!-- 定义BeanNameAutoProxyCreator的Bean后处理器 -->

<bean class="org.springframework.aop.framework.autoproxy.
    BeanNameAutoProxyCreator">

<!-- 指定对满足哪些bean name的bean自动生成业务代理 -->

<property name="beanNames">

<!-- 下面是所有需要自动创建事务代理的Bean -->

<list>

<value>myService</value>

<!-- 下面还可增加需要增加事务逻辑的业务逻辑Bean -->

...

</list>

<!-- 此处可增加其他需要自动创建事务代理的Bean -->

</property>

<!-- 下面定义BeanNameAutoProxyCreator所需的拦截器 -->

<property name="interceptorNames">

<list>

<value>transactionInterceptor</value>

<!-- 此处可增加其他新的Interceptor -->

</list>

</property>

</bean>

一旦增加了如上的配置片段,系统中的业务逻辑方法就有了事务逻辑。这种声明式事务配置方式可以在不同的事务策略之间自由切换。

提示:尽量使用声明式事务配置方式,而不要在代码中完成事务逻辑。

转载于:https://www.cnblogs.com/jadmin/archive/2009/07/19/2206084.html

Spring整合Hibernate(2)相关推荐

  1. 【Spring】Spring系列6之Spring整合Hibernate

    6.Spring整合Hibernate 6.1.准备工作 6.2.示例 com.xcloud.entities.book com.xcloud.dao.book com.xcloud.service. ...

  2. spring整合hibernate事务编程中错误分析

    2019独角兽企业重金招聘Python工程师标准>>> 在spring整合hibernate过程中,我们的配置文件: <?xml version="1.0" ...

  3. 解决在Spring整合Hibernate配置tx事务管理器出现错误的问题

    解决在Spring整合Hibernate配置tx事务管理器出现错误的问题 参考文章: (1)解决在Spring整合Hibernate配置tx事务管理器出现错误的问题 (2)https://www.cn ...

  4. spring整合hibernate步骤及配置文件

    spring整合hibernate,主要达到的目的有以下几点 1.使用Spring的IOC功能管理SessionFactory对象 --LocalSessionFactoryBean 对于Sessio ...

  5. Spring整合Hibernate步骤以及遇到的问题

    spring整合Hibernate步骤以及遇到的问题 文章目录 spring整合Hibernate步骤以及遇到的问题 步骤: 创建实体类: 编写Dao层: 编写server层: spring配置文件 ...

  6. 【spring框架】spring整合hibernate初步

    spring与hibernate做整合的时候,首先我们要获得sessionFactory. 我们一般只需要操作一个sessionFactory,也就是一个"单例",这一点很适合交给 ...

  7. Spring整合Hibernate的步骤

    为什么要整合Hibernate? 1.使用Spring的IOC功能管理SessionFactory对象  LocalSessionFactoryBean 2.使用Spring管理Session对象   ...

  8. Spring整合Hibernate图文步骤

    工具:myeclipse9.0 Spring版本:2.5.6 Hibernate版本:3 昨天花了一下午时间把Spring和Hibernate整合到了一起,今天做一个笔记. 首先建立java Proj ...

  9. Spring整合Hibernate

    整合Hibernate 由 IOC 容器,生成 SessionFactory 对象 使用Spring 的声明式事务 LocalSessionFactoryBean 利用 LocalSessionFac ...

  10. Spring整合Hibernate和Struts2 (SSH)

    1.首先从整合Hibernate开始 2.导入包,这里就把所有的报导进来,包括struts2的,一起导进来 一共29个包 3.编写实体类 package star.july.entity; publi ...

最新文章

  1. Jzzhu and Chocolate
  2. ckeditor富文本编辑器的基本配置设置:
  3. Oracle 基础之数据库管理
  4. new Integer 和 Integer.valueOf 有什么不同
  5. 一文看懂软件测试方法和规范
  6. iOS开发小技巧--高斯模糊框架的应用
  7. deebot扫地机器人怎么清洁_扫地机器人清洁力拼杀,科沃斯机器人DEEBOT N3与小米1S对比评测...
  8. Sqlserver:timestamp数据类型
  9. linux下超简单的ntp时间服务器
  10. 使用HTML5技术控制电脑或手机上的摄像头(转载)
  11. 《Effective Python 2nd》 读书笔记——函数
  12. DIY多快充协议太阳能充电器!----锂电池充电电路
  13. Java代码审计详解
  14. 仇保兴:城市的交通应该尊重什么样的发展战略?
  15. 计算机二级WPS Office考试大纲2021年
  16. C语言:数组排序(插入法排序)
  17. 仿雷电——飞机大战类游戏Ⅰ
  18. java in thread main_linux运行java项目中的main方法,报错:Exception in thread main jav
  19. CAN工具 - PCAN - 半自动化
  20. JS实现仿新浪微博大厅和腾讯微博首页滚动效果_前端开发

热门文章

  1. 想开发一个背单词的学习软件
  2. vscode写python爬虫_如何在vscode中调试python scrapy爬虫
  3. 三角形一条边在另一条的投影长度计算
  4. COM.MYSQL.JDBC.DRIVER 和 COM.MYSQL.CJ.JDBC.DRIVER的区别
  5. 《工程师文化行为自我分享》_文化对于鼓励创新行为至关重要
  6. rnn 简要_注重文化的简要招聘指南
  7. sourceforge_SourceForge依旧re憬未来
  8. 开源xen对比_女实习生在Xen Project上摇摆开源
  9. ASP.NET HyperLink控件NavigateUrl中用到DataBinder.Eval时
  10. jqgrid columnChooser列的自定义及存储和获取