Spring整合Hibernate的价值在于Spring为Hibernate增加了以下内容:
* Session management:Spring为Hibernate的session提供了有效、容易和安全的控制
* Resource management:Spring控制Hibernate的SessionFactories,JDBC datasources及其它相关资源
* Integrated transaction management:完整的事务管理
* Exception wrapping:异常的包装
1. 利用Spring IoC容器创建SessionFactory
可以使用org.springframework.orm.hibernate3.LocalSessionFactoryBean创建SessionFactory实例,共有以下二种方式:
1) 【最佳方案】直接使用Hibernate配置文件hibernate.cfg.xml
Hibernate配置文件hibernate.cfg.xml如下:
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="myeclipse.connection.profile"> com.microsoft.sqlserver.jdbc.SQLServerDriver </property> <property name="connection.url"> jdbc:sqlserver://localhost:1433;databaseName=SSH </property> <property name="connection.username">sa</property> <property name="connection.password"></property> <property name="connection.driver_class"> com.microsoft.sqlserver.jdbc.SQLServerDriver </property> <property name="dialect"> org.hibernate.dialect.SQLServerDialect </property> <mapping resource="cn/qdqn/ssh/entity/UserInfo.hbm.xml" /> </session-factory> </hibernate-configuration>
Spring配置文件中SessionFactory初始化配置方法:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml"> </property> </bean>
2) 在Spring配置文件中整合所有Hibernate配置参数
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/> <property name="url" value="jdbc:sqlserver://localhost:1433;databaseName=SSH"/> <property name="username" value="sa"/> <property name="password" value=""/> </bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"> </property> <property name="mappingResources"> <list> <value>cn/qdqn/ssh/entity/UserInfo.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.SQLServerDialect </prop> <prop key="show_sql">true</prop> </props> </property> </bean>
注意:使用MyEclipse集成SSH时,org.apache.commons.dbcp.BasicDataSource所在的包commons-dbcp-1.2.2.jar不会默认加载,另外还需加载commons-pool-1.4.jar,两者均可在Apache网站commons项目下找到。否则运行程序会出现以下异常:
java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool at java.lang.Class.getDeclaredConstructors0(Native Method) at java.lang.Class.privateGetDeclaredConstructors(Unknown Source) at java.lang.Class.getConstructor0(Unknown Source) at java.lang.Class.getDeclaredConstructor(Unknown Source) ……
2. Hibernate DAO开发
1) 使用Hibernate原生API实现DAO
A. 使用原生API实现DAO
public class UserInfoDAORaw implements IUserInfoDAO { private SessionFactory sessionFactory; public SessionFactory getSessionFactory() { return sessionFactory; } public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public List findAll() { return this.sessionFactory.getCurrentSession() .createQuery("from UserInfo").list(); } 部分代码省略…… }
B. 在applicationContext.xml配置原生DAO Bean
<bean id="userInfoDAORaw" class="cn.qdqn.ssh.dao.UserInfoDAORaw"> <property name="sessionFactory"> <ref bean="sessionFactory" /> </property> </bean>
C. 运行测试
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); UserInfoDAORaw dao=(UserInfoDAORaw)ctx.getBean("userInfoDAORaw"); List<UserInfo> list=dao.findAll(); for(UserInfo info : list){ System.out.println(info.getUserName()+"-"+info.getUserPwd()); }
结论:使用Hibernate原生API实现DAO可以做到Hibernate和Spring完全分离,缺点是无法利用Spring封装Hibernate所提供的额外功能。
2)【最佳方案】使用Spring框架所提供的HibernateDaoSupport类实现DAO
A. 使用MyEclipse反向工程生成Spring 整合Hibernate 的DAO,该DAO继承自Spring的org.springframework.orm.hibernate3.support.HibernateDaoSupport
public class UserInfoDAO extends HibernateDaoSupport { private static final Log log = LogFactory.getLog(UserInfoDAO.class); // property constants public static final String USER_NAME = "userName"; public static final String USER_PWD = "userPwd"; public void save(UserInfo transientInstance) { log.debug("saving UserInfo instance"); try { getHibernateTemplate().save(transientInstance); log.debug("save successful"); } catch (RuntimeException re) { log.error("save failed", re); throw re; } } 部分代码省略…… }
B. 在applicationContext.xml配置DAO Bean
<bean id="userInfoDAO" class="cn.qdqn.ssh.dao.UserInfoDAO"> <property name="sessionFactory"> <ref bean="sessionFactory" /> </property> </bean>
C. 运行测试
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); UserInfoDAORaw dao = (UserInfoDAORaw)ctx.getBean("userInfoDAO"); List<UserInfo> list = dao.findAll(); for(UserInfo info : list) { System.out.println(info.getUserName()+"-"+info.getUserPwd()); }
注意:HibernateDaoSupport通过getHibernateTemplate()方法得到HibernateTemplate实例进行保存、删除等操作,但是HibernateTemplate默认不进行事务处理,而在Hibernate中这些操作必须在事务下执行才能得到正确的结果,因此必须使用Spring声明式事务管理。
3. 使用Spring声明式事务管理
1) 使用Spring 1.x 的事务代理类进行事务管理
A. 在applicationContext.xml中声明事务管理器,注入sessionFactory属性
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref local="sessionFactory" /> </property> </bean>
B. 在applicationContext.xml中使用Spring AOP代理方式实现声明式事务
<bean id="userInfoDAOProxy" class= "org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!--必须为true时CGLIB才不用强制编写DAO接口--> <property name="proxyTargetClass"> <value>true</value> </property> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="target"> <ref bean="userInfoDAO"/> </property> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean>