Spring整合Hibernate总结

来源:互联网 发布:酒店网络电视解决方案 编辑:程序博客网 时间:2024/05/29 06:43

  时至今日,可能极少有J2EE应用会直接以JDBC方式进行持久化层访问。毕竟,用面向对象的程序设计语言来访问关系数据库,是一件让人沮丧的事情。大部分时候,J2EE应用都会以ORM框架来进行持久层访问,在所有的ORM框架中,HIBERNATE以其灵巧,轻便的封装赢得了众多开发者的亲睐.

1.Spring提供DAO支持
      Spring提供了多种数据库访问技术的DAO支持,包括Hibernate,JDO,TopLink,iBatis,OJB等。Spring可以使用相同的访问模式,不同的数据库访问技术。就Hibernate的持久层访问技术而言。Spring提供了如下3个工具类(或接口)来支持DAO组件的实现。
HibernateDaoSuppert
HibernateTemplate
HIbernateCallBack

 

2.管理Hibernate的SessionFactory
    在进行Hibernate进行持久化层访问时,Hibernate的SessionFactory是一个非常重要的对象,它是单个数据库映射关系编译后的内存镜像。大部分情况下,一个J2EE应用对应一个数据库,也即对应一个SessionFactory对象.
    在纯粹的Hibernate访问中,应用程序需要手动创建SessionFactory实例,可想而知,这不是一个优秀的策略。在实际开发中,希望以一种声明式的方式管理SessionFactory实例,直接以配置文件来管理SessionFactory实例。
    Spring的Ioc容器则提供了更好的管理方式,它不仅以声明式的方式配置了SessionFactory实例,也可以充分利用Ioc容器的作用,为SessionFactory注入数据源引用.

下面是Spring配置文件中配置HibernateSessionFactory的示范代码.


<?xml version="1.0"encoding="GBK"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">

 <!-- 定义数据源Bean,使用C3P0数据源实现-->
 <bean id="dataSource"destroy-method="close">
  <!-- 指定连接数据库的驱动-->
  <propertyname="driverClass"value="com.mysql.jdbc.Driver"/>
  <!-- 指定连接数据库的URL-->
  <propertyname="jdbcUrl"value="jdbc:mysql://localhost/onlinexam"/>
  <!-- 指定连接数据库的用户名-->
  <propertyname="user" value="root"/>
  <!-- 指定连接数据库的密码-->
  <propertyname="password" value="admin"/>
  <!--指定连接数据库连接池的最大连接数 -->
  <propertyname="maxPoolSize" value="40"/>
  <!--指定连接数据库连接池的最小连接数 -->
  <propertyname="minPoolSize" value="1"/>
  <!--指定连接数据库连接池的初始化连接数 -->
  <propertyname="initialPoolSize" value="1"/>
  <!--指定连接数据库连接池的连接的最大空闲时间 -->
  <propertyname="maxIdleTime" value="20"/>
 </bean>

   <bean id="sessionFactory" #FF0000"<org.springframework.orm.hibernate3.LocalSessionFactoryBean">
       <property name="dataSource"ref="dataSource"/>
       <propertyname="mappingResources">
           <list>
    <value>ExamType.hbm.xml</value>
    <value>ExamUser.hbm.xml</value>
    <value>Question.hbm.xml</value>
    <value>Student.hbm.xml</value>
           </list>
       </property>
       <propertyname="hibernateProperties">
           <props>
               <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
               <prop key="show_sql">true</prop>
               <prop key="hibernate.hbm2ddl.auto">update</prop>
               <prop key="hibernate.jdbc.batch_size">20</prop>
           </props>
       </property>
    </bean>
    <!--配置持久化类DAO Bean-->
    <bean id="personDao">
    </bean>
  </beans>

     一旦在Spring的Ioc容器中配置了SessionFactoryBean,它将随应用的启动而加载,可以充分利用Ioc容器的功能,将SessionFactoryBean的注入任何Bean,比如DAO组件,以声明式的方式管理SessionFactory实例,可以让应用在不同数据源之间切换。如果应用更换数据库等持久层资源,只需对配置文件进行简单修改即可。

 

3.使用HibernateTemplate.
     HibernateTemplate提供持久层访问模板,使用HibernateTemplate无须实现特定接口,它只需要提供一个SessionFactory的引用就可以执行持久化操作。SessionFactory对象既可通过构造函数传入,也可以通过设值传入。
  HibernateTemplate()
  HibernateTemplate(org.hibernates.SessionFactorysessionFactory) (这个用得较多一点)
  HibernateTemplate(org.hibernates.SessionFactorysessionFactory,boolean allowCreate)

 HibernateTemplate的常用方法简介
 void delete(Object entity)
 deleteAll(Collection entities)
 find(String queryString)
 findByNameQuery(String queryName)
 get(Class entityClass,Serializable id)
 save(Object entity)
 saveOrUpdate(Object entity)
 update(Object entity)
 setMaxResults(int maxResults) 设置分页的大小

 

例如 下面是一个完整的DAO类的源代码
public class PersonDaoImplimplements PersonDao
{

    privateHibernateTemplate ht = null;
    privateSessionFactory sessionFactory;

    publicvoid setSessionFactory(SessionFactory sessionFactory)
 {
       this.sessionFactory = sessionFactory;
    }

   private  HibernateTemplategetHibernateTemplate()
    {
       if (ht == null)
       {
           ht = new HibernateTemplate(sessionFactory);
       }
  return ht;
    }
   
    publicPerson get(int id)
    {
       return (Person)getHibernateTemplate().get(Person.class, newInteger(id));
    }

      
    public voidsave(Person person)
    {
       getHibernateTemplate().save(person);
    }

   
    public voidupdate(Person person)
    {
       getHibernateTemplate().update(person);
    }

   
    public voiddelete(int id)
    {
       getHibernateTemplate().delete(getHibernateTemplate().get(Person.class,new Integer(id)));
    }

   
    public voiddelete(Person person)
    {
       getHibernateTemplate().delete(person);
    }

   
    public ListfindByName(String name)
    {
       return getHibernateTemplate().find("from Person p where p.name like?" ,name);       
    }

   
    public ListfindAllPerson()
    {
       return getHibernateTemplate().find("from Person");    
    }

 public List getPersonNumber()
 {
  returngetHibernateTemplate().find("select count(distinct p.name) fromPerson as p");
 }
}

 

4.使用HibernateCallBack
     HibernateCallBack是一个接口,该接口包含一个方法doInHibernate(org.hibernate.Sessionsession),该方法只有一个参数Session。在开发中提供HibernateCallBack实现类时,必须实现接口里包含的doInHibernate方法,在该方法体内即可获得HibernateSession的引用,一旦获得了HibernateSession的引用,就可以完全以Hibernate的方式进行数据库访问
    下面的代码对HibernateDaoSupport类进行扩展(虽然Spring 2.0提供了一个分页方法setMaxResults,但仅此一个方法依然不能实现分页查询),这咱扩展是为该类增加了3个分页查询该方法,分页查询时必须直接调用Hibernate的Session完成,因此,必须借用图表HibernateCallBack的帮助。

例如

public class ExtendHibernateDaoSupport extendsHibernateDaoSupport
{

 
 public List findByPage(final String hql,
   final int offset, final intpageSize)
 {

  List list =getHibernateTemplate().executeFind(new HibernateCallback()
   {
    publicObject doInHibernate(Session session)
     throwsHibernateException, SQLException
    {
     Listresult = session.createQuery(hql)
          .setFirstResult(offset)
                      .setMaxResults(pageSize)
          .list();
     returnresult;
    }
   });
  return list;
 }


 
 public List findByPage(final String hql , finalObject value ,
   final int offset, final intpageSize)
 {

  List list =getHibernateTemplate().executeFind(new HibernateCallback()
   {
    publicObject doInHibernate(Session session)
     throwsHibernateException, SQLException
    {
     Listresult = session.createQuery(hql)
                .setParameter(0, value)
          .setFirstResult(offset)
                      .setMaxResults(pageSize)
          .list();
     returnresult;
    }
   });
  return list;
 }


 
 public List findByPage(final String hql, finalObject[] values,
   final int offset, final intpageSize)
 {

  List list =getHibernateTemplate().executeFind(new HibernateCallback()
   {
    publicObject doInHibernate(Session session)
     throwsHibernateException, SQLException
    {
     Queryquery = session.createQuery(hql);
     for(int i = 0 ; i < values.length ; i++)
     {
      query.setParameter(i, values[i]);
     }
     Listresult = query.setFirstResult(offset)
                    .setMaxResults(pageSize)
           .list();
     returnresult;
    }
   });
  return list;
 }
}

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

 

5.实现DAO组件
    为了实现DAO组件,Spring提供了大量的XxxDaoSupport类,这些DAO支持类对于实现DAO组件大有帮助,因为这些DAO支持类已经完成了大量基础性工作,Spring为Hibernate的DAO操作提供了工作类HibernateDaoSupport.该类主要提供了如下两个方法以方便DAO的实现
 public finalHibernateTemplate getHibernateTemplate()
 public final voidsetSessionFactory(SessionFactorysessionFactory)

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

 

下面实现了DAO组件继承了Spring提供的HibernateDaoSupport类,依然实现了PersonDao接口

 public class PersonDaoHibernate extendsHibernateDaoSupport implements PersonDao
{
   
    publicPerson get(int id)
    {
       return (Person)getHibernateTemplate().get(Person.class, newInteger(id));
    }

      
    public voidsave(Person person)
    {
       getHibernateTemplate().save(person);
    }

   
    public voidupdate(Person person)
    {
       getHibernateTemplate().update(person);
    }

   
    public voiddelete(int id)
    {
       getHibernateTemplate().delete(getHibernateTemplate().get(Person.class,new Integer(id)));
    }

   
    public voiddelete(Person person)
    {
       getHibernateTemplate().delete(person);
    }

   
    public ListfindByName(String name)
    {
       return getHibernateTemplate().find("from Person p where p.name like?" ,name);       
    }

   
    public ListfindAllPerson()
    {
       return getHibernateTemplate().find("from Person");    
    }
}

 

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

配置文件详解

Spring整合Hibernate的方式灵活多样。主要是在Spring提供的org.springframework.orm.hibernate3.LocalSessionFactoryBean中进行整合,这个Bean提供了多种整合的方法,晒友阁与您分享:

1.可以通过<property name=”hibernateProperties”>标签将hibernate的配置信息以property的方式写入.

 1     <property name="hibernateProperties"> 2             <props> 3                 <prop key="hibernate.dialet">org.hibernate.dialect.MySQLDialect</prop> 4                 <prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop> 5                 <prop key="hibernate.connection.url">jdbc:mysql://localhost:3306/book</prop> 6                 <prop key="hibernate.connection.username">yuan</prop> 7                 <prop key="hibernate.connection.password">hanyuan9113</prop> 8                 <prop key="hibernate.show_sql">true</prop> 9                 <prop key="hibernate.connection.autocommit">true</prop>10             </props>11         </property>

2.可通过<property name=”configLocation”>标签直接读取hibernate.cfg.xml配置信息

1      <property name="configLocation">2             <value>classpath:hibernate.cfg.xml</value>3        </property>

3.可通过<property name=”dataSource”>标签指定连接池,连接池中有连接数据库的信息

1     <property name="dataSource">2             <ref bean="myDataSource" />3         </property>

Spring整合Hibernate的步骤:

一:用以上三种方法之一配置Hibernate信息,装配LocalSessionFactoryBean

 1 <bean id="sessionFactory" 2         class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 3          4         <property name="hibernateProperties"> 5             <props> 6                 <prop key="hibernate.dialet">org.hibernate.dialect.MySQLDialect</prop> 7                 <prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop> 8                 <prop key="hibernate.connection.url">jdbc:mysql://localhost:3306/book</prop> 9                 <prop key="hibernate.connection.username">yuan</prop>10                 <prop key="hibernate.connection.password">hanyuan9113</prop>11                 <prop key="hibernate.show_sql">true</prop>12                 <prop key="hibernate.connection.autocommit">true</prop>13             </props>14         </property>15 16         <property name="mappingResources">17             <list>18                 <value>com/sunflower/entity/Sutdent.hbm.xml</value>19             </list>20         </property>21 </bean>

其中<property name=”mappingResources”>属性是配置映射文件的。如果有很多映射文件要配置,用这种方法就要为每个映射文件书写配置信息,这样将会非常麻烦。Spring的org.springframework.orm.hibernate3.LocalSessionFactoryBean 提供了一个<property name=”mappingDirectoryLocations”>属性,将所有配置文件放置到一个统一的地方就能一次性进行配置。例如:

1       <property name="mappingDirectoryLocations">2             <list>3                 <value>classpath:com/sunflower/entity</value>4             </list>5         </property>

将一次性配置com.sunflower.entity包下的所有映射文件。

二:装配org.springframework.orm.hibernate3.HibernateTemplate

1     <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">2         <property name="sessionFactory">3             <ref bean="sessionFactory" />4         </property>5     </bean>

HibernateTemplate类是Spring提供给我们进行Hibernate持久层操作的类它对增删查改方法进行了封装,通过这个类我们很方便就能操作数据库<property name=”sessionFactory”>标签配置LocalSessionFactoryBean

三:装配自定义DAO

1   <bean id="studentDao" class="com.sunflower.daoimp.StudentDaoImp">2         <property name="hibernateTemplate">3             <ref bean="hibernateTemplate" />4         </property>5     </bean>

为每个Dao的实现类配置一个HibernateTemplate,然后在Spring配置文件中进行装配,这样就可以使用这个HibernateTemplate进行持久层的操作了。
StudentDaoImp.java:

 1 public class StudentDaoImp extends StudentDaoAdapter { 2     @Override 3     public void saveStudent(Student student) { 4         this.hibernateTemplate.save(student); 5     } 6  7     @Override 8     public Student getStudent(Student student) { 9         return this.hibernateTemplate.get(Student.class, student.getSno());10     }11 }

进行测试,Test.java:

 1 public class Test { 2  3     @org.junit.Test 4     public void saveStudent() { 5         ApplicationContext context = new ClassPathXmlApplicationContext( 6                 "applicationContext.xml"); 7         StudentDao studentDao = (StudentDao) context.getBean("studentDao"); 8  9         Student student = new Student();10 11         student.setCno(4);12         student.setName("喜爱啸");13         student.setScore(70);14 15         studentDao.saveStudent(student);16 17     }18 19 //    @org.junit.Test20     public void getStudent() {21         ApplicationContext context = new ClassPathXmlApplicationContext(22                 "applicationContext.xml");23         StudentDao studentDao = (StudentDao) context.getBean("studentDao");24 25         Student student = new Student();26         student.setSno(15);27         Student s = studentDao.getStudent(student);28 29         System.out.println("name:" + s.getName());30     }31 32 }

需要注意的是,因为这里没有用到事务处理,Hibernate默认是不会自动提交事务的,所以刚开始测试的时候出现数据插入不了数据库的情况。需将事务设置为自动提交才能将 数据插入到数据库中,这里只是为了测试,就改了过来。如顶上所写<prop key=”hibernate.connection.autocommit”>true</prop>