8.2 集成Hibernate3
Hibernate是全自动的ORM框架,能自动为对象生成相应SQL并透明的持久化对象到数据库。
Spring2.5+版本支持Hibernate 3.1+版本,不支持低版本,Spring3.0.5版本提供对Hibernate 3.6.0 Final版本支持。
8.2.1 如何集成
Spring通过使用如下Bean进行集成Hibernate:
- LocalSessionFactoryBean :用于支持XML映射定义读取:
configLocation和configLocations:用于定义Hibernate配置文件位置,一般使用如classpath:hibernate.cfg.xml形式指定;
mappingLocations :用于指定Hibenate映射文件位置,如chapter8/hbm/user.hbm.xml;
hibernateProperties:用于定义Hibernate属性,即Hibernate配置文件中的属性;
dataSource:定义数据源;
hibernateProperties、dataSource用于消除Hibernate配置文件,因此如果使用configLocations指定配置文件,就不要设置这两个属性了,否则会产生重复配置。推荐使用dataSource来指定数据源,而使用hibernateProperties指定Hibernate属性。
- AnnotationSessionFactoryBean:用于支持注解风格映射定义读取,该类继承LocalSessionFactoryBean并额外提供自动查找注解风格配置模型的能力:
annotatedClasses:设置注解了模型类,通过注解指定映射元数据。
packagesToScan:通过扫描指定的包获取注解模型类,而不是手工指定,如“cn.javass.**.model”将扫描cn.javass包及子包下的model包下的所有注解模型类。
接下来学习一下Spring如何集成Hibernate吧:
1、准备jar包:
首先准备Spring对ORM框架支持的jar包:
org.springframework.orm-3.0.5.RELEASE.jar //提供对ORM框架集成 |
下载hibernate-distribution-3.6.0.Final包,获取如下Hibernate需要的jar包:
|
下载slf4j-1.6.1.zip(http://www.slf4j.org/download.html),slf4j是日志系统门面(Simple Logging Facade for Java),用于对各种日志框架提供给一致的日志访问接口,从而能随时替换日志框架(如log4j、java.util.logging):
slf4j-api-1.6.1.jar //核心API slf4j-log4j12-1.6.1.jar //log4j实现 |
将这些jar包添加到类路径中。
2、对象模型定义,此处使用第七章中的UserModel:
- package cn.javass.spring.chapter7;
- public class UserModel {
- private int id;
- private String myName;
- //省略getter和setter
- }
3、Hibernate映射定义(chapter8/hbm/user.hbm.xml),定义对象和数据库之间的映射:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="cn.javass.spring.chapter7.UserModel" table="test">
- <id name="id" column="id"><generator class="native"/></id>
- <property name="myName" column="name"/>
- </class>
- </hibernate-mapping>
4、 数据源定义,此处使用第7章的配置文件,即“chapter7/ applicationContext-resources.xml”文件。
5、 SessionFactory配置定义(chapter8/applicationContext-hibernate.xml):
- <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
- <property name="dataSource" ref="dataSource"/> <!-- 指定数据源 -->
- <property name="mappingResources"> <!-- 指定映射定义 -->
- <list>
- <value>chapter8/hbm/user.hbm.xml</value>
- </list>
- </property>
- <property name="hibernateProperties"> <!--指定Hibernate属性 -->
- <props>
- <prop key="hibernate.dialect">
- org.hibernate.dialect.HSQLDialect
- </prop>
- </props>
- </property>
- </bean>
6、 获取SessionFactory:
- package cn.javass.spring.chapter8;
- //省略import
- public class HibernateTest {
- private static SessionFactory sessionFactory;
- @BeforeClass
- public static void beforeClass() {
- String[] configLocations = new String[] {
- "classpath:chapter7/applicationContext-resources.xml",
- "classpath:chapter8/applicationContext-hibernate.xml"};
- ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations);
- sessionFactory = ctx.getBean("sessionFactory", SessionFactory.class);
- }
- }
此处我们使用了chapter7/applicationContext-resources.xml定义的“dataSource”数据源,通过ctx.getBean("sessionFactory", SessionFactory.class)获取SessionFactory。
7、通过SessionFactory获取Session对象进行创建和删除表:
- @Before
- public void setUp() {
- //id自增主键从0开始
- final String createTableSql = "create memory table test" + "(id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, " + "name varchar(100))";
- sessionFactory.openSession().
- createSQLQuery(createTableSql).executeUpdate();
- }
- @After
- public void tearDown() {
- final String dropTableSql = "drop table test";
- sessionFactory.openSession().
- createSQLQuery(dropTableSql).executeUpdate();
- }
使用SessionFactory创建Session,然后通过Session对象的createSQLQuery创建本地SQL执行创建和删除表。
8、使用SessionFactory获取Session对象进行持久化数据:
- @Test
- public void testFirst() {
- Session session = sessionFactory.openSession();
- Transaction transaction = null;
- try {
- transaction = beginTransaction(session);
- UserModel model = new UserModel();
- model.setMyName("myName");
- session.save(model);
- } catch (RuntimeException e) {
- rollbackTransaction(transaction);
- throw e;
- } finally {
- commitTransaction(session);
- }
- }
- private Transaction beginTransaction(Session session) {
- Transaction transaction = session.beginTransaction();
- transaction.begin();
- return transaction;
- }
- private void rollbackTransaction(Transaction transaction) {
- if(transaction != null) {
- transaction.rollback();
- }
- }
- private void commitTransaction(Session session) {
- session.close();
- }
使用SessionFactory获取Session进行操作,必须自己控制事务,而且还要保证各个步骤不会出错,有没有更好的解决方案把我们从编程事务中解脱出来?Spring提供了HibernateTemplate模板类用来简化事务处理和常见操作。
8.2.2 使用HibernateTemplate
HibernateTimplate模板类用于简化事务管理及常见操作,类似于JdbcTemplate模板类,对于复杂操作通过提供HibernateCallback回调接口来允许更复杂的操作。
接下来示例一下HibernateTemplate的使用:
- @Test
- public void testHibernateTemplate() {
- HibernateTemplate hibernateTemplate =
- new HibernateTemplate(sessionFactory);
- final UserModel model = new UserModel();
- model.setMyName("myName");
- hibernateTemplate.save(model);
- //通过回调允许更复杂操作
- hibernateTemplate.execute(new HibernateCallback<Void>() {
- @Override
- public Void doInHibernate(Session session)
- throws HibernateException, SQLException {
- session.save(model);
- return null;
- }});
- }
通过new HibernateTemplate(sessionFactory) 创建HibernateTemplate模板类对象,通过调用模板类的save方法持久化对象,并且自动享受到Spring管理事务的好处。
而且HibernateTemplate 提供使用HibernateCallback回调接口的方法execute用来支持复杂操作,当然也自动享受到Spring管理事务的好处。
8.2.3 集成Hibernate及最佳实践
类似于JdbcDaoSupport类,Spring对Hibernate也提供了HibernateDaoSupport类来支持一致的数据库访问。HibernateDaoSupport也是DaoSupport实现:
接下来示例一下Spring集成Hibernate的最佳实践:
1、 定义Dao接口,此处使用cn.javass.spring.chapter7.dao. IUserDao:
2、 定义Dao接口实现,此处是Hibernate实现:
- package cn.javass.spring.chapter8.dao.hibernate;
- import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
- import cn.javass.spring.chapter7.UserModel;
- import cn.javass.spring.chapter7.dao.IUserDao;
- public class UserHibernateDaoImpl extends HibernateDaoSupport implements IUserDao {
- private static final String COUNT_ALL_HQL = "select count(*) from UserModel";
- @Override
- public void save(UserModel model) {
- getHibernateTemplate().save(model);
- }
- @Override
- public int countAll() {
- Number count = (Number) getHibernateTemplate().find(COUNT_ALL_HQL).get(0);
- return count.intValue();
- }
- }
此处注意首先Hibernate实现放在dao.hibernate包里,其次实现类命名如UserHibernateDaoImpl,即×××HibernateDaoImpl,当然如果自己有更好的命名规范可以遵循自己的,此处只是提个建议。
3、进行资源配置,使用resources/chapter7/applicationContext-resources.xml:
4、dao定义配置,在chapter8/applicationContext-hibernate.xml中添加如下配置:
- <bean id="abstractDao" abstract="true">
- <property name="sessionFactory" ref="sessionFactory"/>
- </bean>
- <bean id="userDao" class="cn.javass.spring.chapter8.dao.hibernate.UserHibernateDaoImpl" parent="abstractDao"/>
首先定义抽象的abstractDao,其有一个sessionFactory属性,从而可以让继承的子类自动继承sessionFactory属性注入;然后定义userDao,且继承abstractDao,从而继承sessionFactory注入;我们在此给配置文件命名为applicationContext-hibernate.xml表示Hibernate实现。
5、 最后测试一下吧(cn.javass.spring.chapter8. HibernateTest):
- @Test
- public void testBestPractice() {
- String[] configLocations = new String[] {
- "classpath:chapter7/applicationContext-resources.xml",
- "classpath:chapter8/applicationContext-hibernate.xml"};
- ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations);
- IUserDao userDao = ctx.getBean(IUserDao.class);
- UserModel model = new UserModel();
- model.setMyName("test");
- userDao.save(model);
- Assert.assertEquals(1, userDao.countAll());
- }
和Spring JDBC框架的最佳实践完全一样,除了使用applicationContext-hibernate.xml代替了applicationContext-jdbc.xml,其他完全一样。也就是说,DAO层的实现替换可以透明化。
8.2.4 Spring+Hibernate的CRUD
Spring+Hibernate CRUD(增删改查)我们使用注解类来示例,让我们看具体示例吧:
1、首先定义带注解的模型对象UserModel2:
- 使用JPA注解@Table指定表名映射;
- 使用注解@Id指定主键映射;
- 使用注解@ Column指定数据库列映射;
- package cn.javass.spring.chapter8;
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.GeneratedValue;
- import javax.persistence.GenerationType;
- import javax.persistence.Id;
- import javax.persistence.Table;
- @Entity
- @Table(name = "test")
- public class UserModel2 {
- @Id @GeneratedValue(strategy = GenerationType.AUTO)
- private int id;
- @Column(name = "name")
- private String myName;
- //省略getter和setter
- }
2、 定义配置文件(chapter8/applicationContext-hibernate2.xml):
2.1、 定义SessionFactory:
此处使用AnnotationSessionFactoryBean通过annotatedClasses属性指定注解模型来定义映射元数据;
- <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
- <property name="dataSource" ref="dataSource"/> <!-- 1、指定数据源 -->
- <property name="annotatedClasses"> <!-- 2、指定注解类 -->
- <list><value>cn.javass.spring.chapter8.UserModel2</value></list>
- </property>
- <property name="hibernateProperties"><!-- 3、指定Hibernate属性 -->
- <props>
- <prop key="hibernate.dialect">
- org.hibernate.dialect.HSQLDialect
- </prop>
- </props>
- </property>
- </bean>
2.2、定义HibernateTemplate :
- <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
- <property name="sessionFactory" ref="sessionFactory"/>
- </bean>
3、最后进行CURD测试吧:
- @Test
- public void testCURD() {
- String[] configLocations = new String[] {
- "classpath:chapter7/applicationContext-resources.xml",
- "classpath:chapter8/applicationContext-hibernate2.xml"};
- ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations);
- HibernateTemplate hibernateTemplate = ctx.getBean(HibernateTemplate.class);
- UserModel2 model = new UserModel2();
- model.setMyName("test");
- insert(hibernateTemplate, model);
- select(hibernateTemplate, model);
- update(hibernateTemplate, model);
- delete(hibernateTemplate, model);
- }
- private void insert(HibernateTemplate hibernateTemplate, UserModel2 model) {
- hibernateTemplate.save(model);
- }
- private void select(HibernateTemplate hibernateTemplate, UserModel2 model) {
- UserModel2 model2 = hibernateTemplate.get(UserModel2.class, 0);
- Assert.assertEquals(model2.getMyName(), model.getMyName());
- List<UserModel2> list = hibernateTemplate.find("from UserModel2");
- Assert.assertEquals(list.get(0).getMyName(), model.getMyName());
- }
- private void update(HibernateTemplate hibernateTemplate, UserModel2 model) {
- model.setMyName("test2");
- hibernateTemplate.update(model);
- }
- private void delete(HibernateTemplate hibernateTemplate, UserModel2 model) {
- hibernateTemplate.delete(model);
- }
Spring集成Hibernate进行增删改查是不是比Spring JDBC方式简单许多,而且支持注解方式配置映射元数据,从而减少映射定义配置文件数量。
原文地址:http://sishuok.com/forum/blogPost/list/2497.html