Hibernate的DAO实现
10.7 Hibernate的DAO实现DAO对象是模块化的数据库访问组件,DAO对象通常包括:对持久化类的基本CRUD操作(插入、查询、更新、删除)操作。Spring对Hibernate的DAO实现提供了良好的支持。主要有如下两种方式的DAO实现:
q 继承HibernateDaoSupport的实现DAO
q 基于Hibernate3.0实现DAO
不管采用哪一种实现,这种DAO对象都极好地融合到Spring的ApplicationContext中,遵循依赖注入模式,提高解耦。
10.7.1 继承HibernateDaoSupport实现DAOSpring为Hibernate的DAO提供工具类:HibernateDaoSupport。该类主要提供如下两个方法,方便DAO的实现:
q public final HibernateTemplate getHibernateTemplate()
q public final void setSessionFactory(SessionFactory sessionFactory)
其中,setSessionFactory方法用来接收Spring的ApplicationContext的依赖注入,可接收配置在Spring的SessionFactory实例,getHibernateTemplate方法则用来根据刚才的SessionFactory产生Session,最后生成HibernateTemplate来完成数据库访问。
典型的继承HibernateDaoSupport的DAO实现的代码如下:
public class PersonDAOHibernate extends HibernateDaoSupport implements PersonDAO { //采用log4j来完成调试时的日志功能 private static Log log = LogFactory.getLog(NewsDAOHibernate.class); //返回全部的人的实例 public List getPersons() { //通过HibernateTemplate的find方法返回Person的全部实例 return getHibernateTemplate().find("from Person"); } /** * 根据主键返回特定实例 * @ return 特定主键对应的Person实例 * @ param 主键值 public News getPerson(int personid) { return (Person)getHibernateTemplate().get(Person.class, new Integer(personid)); } /** * @ person 需要保存的Person实例 */ public void savePerson(Person person) { getHibernateTemplate().saveOrUpdate(person); } /** * @ param personid 需要删除Person实例的主键 * / public void removePerson(int personid) { //先加载特定实例 Object p = getHibernateTemplate().load(Person.class, new Integer(personid)); //删除特定实例 getHibernateTemplate().delete(p); } }
可以与前面的PersonDAOHibernate对比,会发现代码量大大减少。事实上,DAO的实现依然借助于HibernateTemplate的模板访问方式,只是,HibernateDaoSupport将依赖注入SessionFactory的工作已经完成,获取HibernateTemplate的工作也已完成。该DAO的配置必须依赖于SessionFactory,具体的配置如下:
<?xml version="1.0" encoding="gb2312"?> <!-- Spring配置文件的DTD定义--> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <!-- Spring配置文件的根元素是beans--> <beans> <!--定义数据源,该bean的ID为dataSource--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <!-- 指定数据库驱动--> <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property> <!-- 指定连接数据库的URL--> <property name="url"><value>jdbc:mysql://wonder:3306/j2ee</value></property> <!-- root为数据库的用户名--> <property name="username"><value>root</value></property> <!-- pass为数据库密码--> <property name="password"><value>pass</value></property> </bean> <!--定义Hibernate的SessionFactory--> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <!-- 依赖注入数据源,注入正是上文定义的dataSource> <property name="dataSource"><ref local="dataSource"/></property> <!-- mappingResouces属性用来列出全部映射文件> <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> <!-- 不同数据库连接,启动时选择create,update,create-drop--> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- 配置Person持久化类的DAO bean--> <bean id="personDAO" class="lee. PersonDAOHibernate"> <!-- 采用依赖注入来传入SessionFactory的引用> <property name="sessionFactory"><ref local="sessionFactory"/></property> </bean> </beans>
程序中可以通过显式的编码来获得personDAO bean,然后执行CRUD操作。也可通过依赖注入,将personDAO的实例注入其他bean属性,再执行CRUD操作。
在继承HibrnateDaoSupport的DAO实现里,Hibernate Session的管理完全不需要Hibernate代码打开,而由Spring来管理。Spring会根据实际的操作,采用“每次事务打开一次session”的策略,自动提高数据库访问的性能。
10.7.1基于Hibernate3.0实现DAOHibernate3.0.1提供了一种新的技术:"contextual Sessions"。通过此机制,Hibernate可以自己管理Session,从而保证每次事务一个Session。该机制类似于Spring的每次事务一次Hibernate Session的同步策略。
Hibernate的"contextual Sessions",是通过SessionFactory的getCurrentSession()方法实现的,该方法会返回由当前JTA事务保持的Session,如果当前JTA事务关联的Session不存在,系统打开一次新的Session,并关联到当前的JTA事务,如果当前JTA事务关联的Session已经存在,则直接返回该Session即可。执行该操作的前提是Hibernate处于事务管理下。通常,Spring为Hibernate提供事务管理。
基于Hibernate 3.0的DAO的实现,只需Spring注入SessionFactory,然后由Hibernate自己管理Session。即:通过SessionFactory的getCurrentSession方法,返回当前事务关联的Session。持久化操作在Session管理如常进行。完整的基于Hibernate3.0的DAO实现的代码如下
public class PersonDaoImpl implements PersonDao { //私有成员变量保存SessionFactory private SessionFactory sessionFactory; /** * 依赖注入SessionFactory必须的setter方法 * @ sessionFactory */ public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } /** * 根据名字查找Person的实例。 * @param name需要查找的 Person的名字 * @return 匹配名字的Person实例的集合 */ public Collection findPersonsByName(String name) { return this.sessionFactory.getCurrentSession() .createQuery("from lee.Person p where p.name=?") .setParameter(0, name) .list(); } /** * 根据Person id加再Person实例。 * @param id需要load的 Person实例 * @return 特定id的Person实例。 */ public Person findPersonsById(int id) { return (Person)this.sessionFactory.getCurrentSession() .load(Person.class,new Integer(id)) } }
该DAO的数据库访问方式,类似于传统的Hibernate的访问,区别在于获取Session的方式不同。传统的Hibernate的SessionFactory,采用工具类HibernateUtils来保存成静态成员变量,每次采用HibernateUtils打开Session。
传统的Session访问方式,很容易造成“每次数据库操作打开一次Session”的方式,该方式效率低下,也是Hibernate不推荐采用的策略。Hibernate推荐采用“每次事务打开一次Session”。基于该原因,Hibernate3.0.1提供"contextual Sessions”的技术,最终达到与继承HibernateDaoSupport的DAO实现相同的目的。
同样,此DAO bean也需要配置在Spring的上下文中,需要依赖于SessionFactory bean。SessionFactory bean由Spring在运行时动态为DAO bean注入。具体的配置文件,读者可参考上文的配置文件写出。