时至今日,可能极少有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配置文件中配置Hibernate SessionFactory的示范代码.
<?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/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/onlinexam"/> <!-- 指定连接数据库的用户名 --> <property name="user" value="root"/> <!-- 指定连接数据库的密码 --> <property name="password" value="admin"/> <!-- 指定连接数据库连接池的最大连接数 --> <property name="maxPoolSize" value="40"/> <!-- 指定连接数据库连接池的最小连接数 --> <property name="minPoolSize" value="1"/> <!-- 指定连接数据库连接池的初始化连接数 --> <property name="initialPoolSize" value="1"/> <!-- 指定连接数据库连接池的连接的最大空闲时间 --> <property name="maxIdleTime" value="20"/> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mappingResources"> <list> <value>ExamType.hbm.xml</value> <value>ExamUser.hbm.xml</value> <value>Question.hbm.xml</value> <value>Student.hbm.xml</value> </list> </property> <property name="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" class="com.PersonImple"> </bean> </beans>
3.使用HibernateTemplate.
HibernateTemplate提供持久层访问模板,使用HibernateTemplate无须实现特定接口,它只需要提供一个SessionFactory的引用就可以执行持久化操作。SessionFactory对象既可通过构造函数传入,也可以通过设值传入。
HibernateTemplate()
HibernateTemplate(org.hibernates.SessionFactory sessionFactory) (这个用得较多一点)
HibernateTemplate(org.hibernates.SessionFactory sessionFactory,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 PersonDaoImpl implements PersonDao { private HibernateTemplate ht = null; private SessionFactory sessionFactory; public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } private HibernateTemplate getHibernateTemplate() { if (ht == null) { ht = new HibernateTemplate(sessionFactory); } return ht; } public Person get(int id) { return (Person)getHibernateTemplate().get(Person.class, new Integer(id)); } public void save(Person person) { getHibernateTemplate().save(person); } public void update(Person person) { getHibernateTemplate().update(person); } public void delete(int id) { getHibernateTemplate().delete(getHibernateTemplate().get(Person.class, new Integer(id))); } public void delete(Person person) { getHibernateTemplate().delete(person); } public List findByName(String name) { return getHibernateTemplate().find("from Person p where p.name like ?" , name); } public List findAllPerson() { return getHibernateTemplate().find("from Person "); } public List getPersonNumber() { return getHibernateTemplate().find("select count(distinct p.name) from Person as p"); } }
4.使用HibernateCallBack
HibernateCallBack是一个接口,该接口包含一个方法doInHibernate(org.hibernate.Session session),该方法只有一个参数Session。在开发中提供HibernateCallBack实现类时,必须实现接口里包含的doInHibernate方法,在该方法体内即可获得Hibernate Session的引用,一旦获得了Hibernate Session的引用,就可以完全以Hibernate的方式进行数据库访问。
下面的代码对HibernateDaoSupport类进行扩展(虽然Spring 2.0提供了一个分页方法setMaxResults,但仅此一个方法依然不能实现分页查询),这咱扩展是为该类增加了3个分页查询该方法,分页查询时必须直接调用Hibernate的Session完成,因此,必须借用图表HibernateCallBack的帮助。
例如
public class ExtendHibernateDaoSupport extends HibernateDaoSupport { public List findByPage(final String hql, final int offset, final int pageSize) { List list = getHibernateTemplate().executeFind(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException, SQLException { List result = session.createQuery(hql) .setFirstResult(offset) .setMaxResults(pageSize) .list(); return result; } }); return list; } 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 { List result = session.createQuery(hql) .setParameter(0, value) .setFirstResult(offset) .setMaxResults(pageSize) .list(); return result; } }); return list; } 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; } }
说明:
Spring提供的 XxxTemplate和XxxCallBack互为补充,二者体现了Spring框架设计的精华:XxxTemplate对通用操作进行封装,而XxxCallBack解决了封装后灵活性不足的缺陷。
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接口。
public class PersonDaoHibernate extends HibernateDaoSupport implements PersonDao { public Person get(int id) { return (Person)getHibernateTemplate().get(Person.class, new Integer(id)); } public void save(Person person) { getHibernateTemplate().save(person); } public void update(Person person) { getHibernateTemplate().update(person); } public void delete(int id) { getHibernateTemplate().delete(getHibernateTemplate().get(Person.class, new Integer(id))); } public void delete(Person person) { getHibernateTemplate().delete(person); } public List findByName(String name) { return getHibernateTemplate().find("from Person p where p.name like ?" , name); } public List findAllPerson() { return getHibernateTemplate().find("from Person "); } }
说明:
在继承HibernateDaoSupport的DAO实现里,Hibernate Session的管理完成不需要打开代码,而由Spring来管理。Spring会根据实际的操作,采用"每次事务打开一次Session"的策略,自动提高数据库访问的性能