`

Spring3整合Hibernate3

    博客分类:
  • SSH
阅读更多

6.5  Spring整合Hibernate
时至今日,可能极少有J2EE应用会直接以JDBC方式进行持久层访问。毕竟,用面向对象的程序设计语言来访问关系型数据库,是一件让人沮丧的事情。大部分时候,J2EE应用都会以ORM框架来进行持久层访问,在所有的ORM框架中,Hibernate以其灵巧、轻便的封装赢得了众多开发者的青睐。
Spring具有良好的开放性,能与大部分ORM框架良好整合。下面将详细介绍Spring与Hibernate的整合。
6.5.1  Spring提供的DAO支持
DAO模式是一种标准的J2EE设计模式,DAO模式的核心思想是,所有的数据库访  问,都通过DAO组件完成,DAO组件封装了数据库的增、删、改等原子操作。而业务逻辑组件则依赖于DAO组件提供的数据库原子操作,完成系统业务逻辑的实现。
对于J2EE应用的架构,有非常多的选择,但不管细节如何变换,J2EE应用都大致可分为如下3层:
  ● 表现层。
  ● 业务逻辑层。
  ● 数据持久层。
轻量级J2EE架构以Spring IoC容器为核心,承上启下。其向上管理来自表现层的Action,向下管理业务逻辑层组件,同时负责管理业务逻辑层所需的DAO对象。各层之间负责传值的是值对象,也就是JavaBean实例。
图6.5精确地描绘了轻量级J2EE架构的大致情形。
DAO组件是整个J2EE应用的持久层访问的重要组件,每个J2EE应用的底层实现都难以离开DAO组件的支持。Spring对实现DAO组件提供了许多工具类,系统的DAO组件可通过继承这些工具类完成,从而可以更加简便地实现DAO组件。
Spring的DAO支持,允许使用相同的方式、不同的数据访问技术,如JDBC、Hibernate或JDO。Spring的DAO在不同的持久层访问技术上提供抽象,应用的持久层访问基于Spring的DAO抽象。因此,应用程序可以在不同的持久层技术之间切换。
Spring提供了一系列的抽象类,这些抽象将被作为应用中DAO实现类的父类。通过继承这些抽象类,Spring简化了DAO的开发步骤,能以一致的方式使用数据库访问技术。不管底层采用JDBC、JDO或Hibernate,应用中都可采用一致的编程模型。

 

 

应用的DAO类继承这些抽象类,会大大简化应用的开发。最大的好处是,继承这些抽象类的DAO能以一致的方式访问数据库,意味着应用程序可以在不同的持久层访问技术中切换。
除此之外,Spring提供了一致的异常抽象,将原有的Checked异常转换包装成Runtime异常,因而,编码时无须捕获各种技术中特定的异常。Spring DAO体系中的异常,都继承DataAccessException,而DataAccessException异常是Runtime的,无须显式捕捉。通过DataAccessException的子类包装原始异常信息,从而保证应用程序依然可以捕捉到原始异常信息。
Spring提供了多种数据库访问技术的DAO支持,包括Hibernate、JDO、TopLink、iBatis、OJB等。Spring可以使用相同的访问模式、不同的数据库访问技术。就Hibernate的持久层访问技术而言,Spring提供了如下3个工具类(或接口)来支持DAO组件的实现:
  ● HibernateDaoSupport。
  ● HibernateTemplate。
  ● HibernateCallBack。

6.5.2  管理Hibernate的SessionFactory
前面介绍Hibernate时已经知道,在通过Hibernate进行持久层访问时,Hibernate的SessionFactory是一个非常重要的对象,它是单个数据库映射关系编译后的内存镜像。大部分情况下,一个J2EE应用对应一个数据库,也即对应一个SessionFactory对象。
在纯粹的Hibernate访问中,应用程序需要手动创建SessionFactory实例,可想而知,这不是一个优秀的策略。在实际开发中,希望以一种声明式的方式管理SessionFactory实例,直接以配置文件来管理SessionFactory实例,在示范Struts的PlugIn扩展点时,大致示范了这种方式(请参阅2.12.1节的内容)。
Spring的IoC容器则提供了更好的管理方式,它不仅能以声明式的方式配置Session- Factory实例,也可充分利用IoC容器的作用,为SessionFactory注入数据源引用。
下面是Spring配置文件中配置Hibernate SessionFactory的示范代码:

<?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 id="sessionFactory" class="org.springframework.orm.hibernate3. 
    LocalSessionFactoryBean"> 
        <!-- 依赖注入数据源,正是上文定义的dataSource --> 
        <property name="dataSource" ref="dataSource"/> 
        <!-- mappingResources属性用来列出全部映射文件 --> 
        <property name="mappingResources"> 
              <list> 
                  <!-- 以下用来列出所有的PO映射文件 --> 
                <value>lee/MyTest.hbm.xml</value> 
              </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> 
</beans> 

 一旦在Spring的IoC容器中配置了SessionFactory Bean,它将随应用的启动而加载,并可以充分利用IoC容器的功能,将SessionFactory Bean注入任何Bean,比如DAO组件。一旦DAO组件获得了SessionFactory Bean的引用,就可以完成实际的数据库访问。
当然,Spring也支持访问容器数据源。如果需要使用容器数据源,可将数据源Bean修改成如下配置:

<!-- 此处配置JNDI数据源 --> 
<bean id="myDataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 
    <property name="jndiName"> 
        <!-- 指定数据源的JNDI --> 
        <value>java:comp/env/jdbc/myds</value> 
    </property> 
</bean> 

 可见,以声明式的方式管理SessionFactory实例,可以让应用在不同数据源之间切换。如果应用更换数据库等持久层资源,只需对配置文件进行简单修改即可。
提示:以声明式的方式管理SessionFactory,非常类似于早期将数据库服务的相关信息放在web.xml文件中进行配置。这种方式是为了提供更好的适应性,当持久层服务需要更改时,应用代码无须任何改变。

6.5.3  使用HibernateTemplateHibernateTemplate提供持久层访问模板.
使用HibernateTemplate无须实现特定接口,它只需要提供一个SessionFactory的引用就可执行持久化操作。SessionFactory对象既可通过构造参数传入,也可通过设值方式传入。HibernateTemplate提供如下3个构造函数:
  ● HibernateTemplate()。
  ● HibernateTemplate(org.hibernate.SessionFactory sessionFactory)。
  ● HibernateTemplate(org.hibernate.SessionFactory sessionFactory, boolean allowCreate)。
第一个构造函数,构造一个默认的HibernateTemplate实例。因此,使用Hibernate- Template实例之前,还必须使用方法setSessionFactory(SessionFactory sessionFactory)来为HibernateTemplate传入SessionFactory的引用。
第二个构造函数,在构造时已经传入SessionFactory引用。
第三个构造函数,其boolean型参数表明,如果当前线程已经存在一个非事务性的Session,是否直接返回此非事务性的Session。
在Web应用中,通常启动时自动加载ApplicationContext,SessionFactory和DAO对象都处在Spring上下文管理下,因此无须在代码中显式设置,可采用依赖注入完成Session- Factory和DAO的解耦,依赖关系通过配置文件来设置,如下所示:

<?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> 
              </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> 
</beans> 

 在PersonDao组件中,所有的持久化操作都通过HibernateTemplate实例完成,而HibernateTemplate操作数据库非常简洁,大部分CRUD操作都可通过一行代码解决问题。下面介绍如何通过HibernateTemplate进行持久层访问。
HibernateTemplate提供了非常多的常用方法来完成基本的操作,比如通常的增加、删除、修改、查询等操作,Spring 2.0更增加了对命名SQL查询的支持,也增加了对分页的支持。大部分情况下,使用Hibernate的常规用法,就可完成大多数DAO对象的CRUD操作。下面是HibernateTemplate的常用方法简介:
  ● void delete(Object entity),删除指定持久化实例。
  ● deleteAll(Collection entities),删除集合内全部持久化类实例。
  ● find(String queryString),根据HQL查询字符串来返回实例集合。
  ● findByNamedQuery(String queryName),根据命名查询返回实例集合。
  ● get(Class entityClass, Serializable id),根据主键加载特定持久化类的实例。
  ● save(Object entity),保存新的实例。
  ● saveOrUpdate(Object entity),根据实例状态,选择保存或者更新。
  ● update(Object entity),更新实例的状态,要求entity是持久状态。
  ● setMaxResults(int maxResults),设置分页的大小。
下面是一个完整DAO类的源代码:

public class PersonDaoImpl implements PersonDao 
{ 
    //执行持久化操作的HibernateTemplate实例 
    private HibernateTemplate ht = null; 
    private SessionFactory sessionFactory; 
    //该DAO组件持久化操作所需的SessionFactory对象 
    public void setSessionFactory(SessionFactory sessionFactory) 
    { 
        this.sessionFactory = sessionFactory; 
    } 
    //用于根据SessionFactory实例返回HibernateTemplate实例的方法 
    private  HibernateTemplate getHibernateTemplate() 
    { 
        if (ht == null) 
        { 
              ht = new HibernateTemplate(sessionFactory); 
        } 
        return ht; 
    } 
    /** 
     * 加载人实例 
     * @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 findByName(String name) 
    { 
        return getHibernateTemplate().find("from Person p where p.name 
        like ?" , name); 
    } 
    /** 
     * 返回全部的Person实例 
     * @return 全部的Person实例 
     */ 
    public List findAllPerson() 
    { 
        return getHibernateTemplate().find("from Person "); 
    } 
} 

 通过上面实现DAO组件的代码可以看出,通过HibernateTemplate进行持久层访问的代码如此清晰,大部分CRUD操作一行代码即可完成,完全无须Hibernate访问那些繁琐的步骤。而且,一旦DAO组件获得了SessionFactory的引用,即可很轻易地创建HibernateTemplate实例。
提示:HibernateTemplate是Spring众多模板工具类之一,Spring正是通过这种简便地封装,完成了开发中大量需要重复执行的工作。

6.5.4  使用HibernateCallBackHibernateTemplate还提供了一种更加灵活的方式来操作数据库,通过这种方式可以完全使用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); 
                    } 
                    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 >PROPAGATION_REQUIRED</prop> 
                <prop >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> 

 一旦增加了如上的配置片段,系统中的业务逻辑方法就有了事务逻辑。这种声明式事务配置方式可以在不同的事务策略之间自由切换。
提示:尽量使用声明式事务配置方式,而不要在代码中完成事务逻辑。

  • 大小: 15.6 KB
分享到:
评论
2 楼 otgtiogtr 2015-04-08  
很好 我的第一次就是看了这个才成功的
1 楼 nankeermeng 2012-04-19  
总结的挺好!看了你的总结我解决了一个常识问题。谢谢!!!

相关推荐

    起点小说解锁.js

    起点小说解锁.js

    299-煤炭大数据智能分析解决方案.pptx

    299-煤炭大数据智能分析解决方案.pptx

    299-教育行业信息化与数据平台建设分享.pptx

    299-教育行业信息化与数据平台建设分享.pptx

    基于Springboot+Vue酒店客房入住管理系统-毕业源码案例设计.zip

    网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代,所以对于信息的宣传和管理就很关键。系统化是必要的,设计网上系统不仅会节约人力和管理成本,还会安全保存庞大的数据量,对于信息的维护和检索也不需要花费很多时间,非常的便利。 网上系统是在MySQL中建立数据表保存信息,运用SpringBoot框架和Java语言编写。并按照软件设计开发流程进行设计实现。系统具备友好性且功能完善。 网上系统在让售信息规范化的同时,也能及时通过数据输入的有效性规则检测出错误数据,让数据的录入达到准确性的目的,进而提升数据的可靠性,让系统数据的错误率降至最低。 关键词:vue;MySQL;SpringBoot框架 【引流】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes

    时间复杂度的一些相关资源

    时间复杂度是计算机科学中用来评估算法效率的一个重要指标。它表示了算法执行时间随输入数据规模增长而变化的趋势。当我们比较不同算法的时间复杂度时,实际上是在比较它们在不同输入规模下的执行效率。 时间复杂度通常用大O符号来表示,它描述了算法执行时间上限的增长率。例如,O(n)表示算法执行时间与输入数据规模n呈线性关系,而O(n^2)则表示算法执行时间与n的平方成正比。当n增大时,O(n^2)算法的执行时间会比O(n)算法增长得更快。 在比较时间复杂度时,我们主要关注复杂度的增长趋势,而不是具体的执行时间。这是因为不同计算机硬件、操作系统和编译器等因素都会影响算法的实际执行时间,而时间复杂度则提供了一个与具体实现无关的评估标准。 一般来说,时间复杂度越低,算法的执行效率就越高。因此,在设计和选择算法时,我们通常希望找到时间复杂度尽可能低的方案。例如,在排序算法中,冒泡排序的时间复杂度为O(n^2),而快速排序的时间复杂度在平均情况下为O(nlogn),因此在处理大规模数据时,快速排序通常比冒泡排序更高效。 总之,时间复杂度是评估算法效率的重要工具,它帮助我们了解算法在不同输入规模下的性

    安全承诺书-施工(单位版).docx

    5G通信行业、网络优化、通信工程建设资料

    基于Springboot+Vue人口老龄化社区服务与管理平台-毕业源码案例设计.zip

    网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代,所以对于信息的宣传和管理就很关键。系统化是必要的,设计网上系统不仅会节约人力和管理成本,还会安全保存庞大的数据量,对于信息的维护和检索也不需要花费很多时间,非常的便利。 网上系统是在MySQL中建立数据表保存信息,运用SpringBoot框架和Java语言编写。并按照软件设计开发流程进行设计实现。系统具备友好性且功能完善。 网上系统在让售信息规范化的同时,也能及时通过数据输入的有效性规则检测出错误数据,让数据的录入达到准确性的目的,进而提升数据的可靠性,让系统数据的错误率降至最低。 关键词:vue;MySQL;SpringBoot框架 【引流】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes

    node-v12.22.6-sunos-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    通信工程施工作业现场高危险源控制图集.docx

    5G通信行业、网络优化、通信工程建设资料

    毕设绝技《基于小程序的交友系统的设计与实现》

    《基于小程序的交友系统的设计与实现》是一个融合了小程序技术和社交功能的毕业设计项目。该项目旨在通过开发一款小程序,为用户提供一个便捷、有趣的交友平台,满足用户寻找新朋友、拓展社交圈的需求。 一、项目背景与目标 随着移动互联网的普及,小程序以其轻便、易用的特性受到了广大用户的喜爱。本项目旨在利用小程序技术开发一款交友系统,通过简洁明了的界面设计和丰富多样的社交功能,吸引用户参与并提升用户体验。通过实现这一系统,旨在帮助用户拓展社交圈,增进人际关系,并推动社交领域的创新与发展。 二、系统设计与功能实现 用户注册与登录:系统提供用户注册与登录功能,确保用户信息的真实性和安全性。用户可以通过手机号或第三方社交账号进行注册和登录。 个人资料展示:用户可以在个人资料页面展示自己的基本信息、兴趣爱好、照片等,以便其他用户了解并产生互动。 附近的人:系统通过定位功能展示附近的其他用户,用户可以浏览附近的人的信息,并主动发起聊天或交友请求。 聊天功能:系统提供一对一的聊天功能,用户可以与感兴趣的人进行实时交流,增进彼此的了解。 活动组织:用户可以发起或参与各类线下活动,如聚会、运动、旅行

    安全生产教育培训制度.doc

    5G通信行业、网络优化、通信工程建设资料

    shampoo-sales.csv

    shampoo-sales.csv

    59-《煤矿测量规程(1989版)》150.pdf

    59-《煤矿测量规程(1989版)》150.pdf

    node-v12.18.1-sunos-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v12.22.3-sunos-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    项目代维费报价书.doc

    5G通信行业、网络优化、通信工程建设资料。

    AXIS T864 系列多通道 PoE+ 同轴电缆刀片套件 AXIS T8648 PoE+ 同轴电缆刀片紧凑型套件安装指南

    AXIS T864 系列多通道 AXIS T8646 PoE+ 同轴电缆刀片套件 AXIS T8648 PoE+ 同轴电缆刀片紧凑型套件安装指南

    MATLAB学习个人笔记总结.7z

    MATLAB学习个人笔记总结.7z

    课设&大作业-毕业设计基于SSM的毕业设计论文题目审核及选题管理系统.zip

    【资源说明】【毕业设计】 1、该资源内项目代码都是经过测试运行成功,功能正常的情况下才上传的,请放心下载使用。 2、适用人群:主要针对计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、数学、电子信息等)的同学或企业员工下载使用,具有较高的学习借鉴价值。 3、不仅适合小白学习实战练习,也可作为大作业、课程设计、毕设项目、初期项目立项演示等,欢迎下载,互相学习,共同进步!

    驻地网施工组织设计方案.doc

    5G通信、网络优化与通信建设

Global site tag (gtag.js) - Google Analytics