时至今日,可能极少有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>