跟我学Spring3(8.2):对ORM的支持之集成Hibernate3

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包:

hibernate3.jar                       //核心包

lib\required\antlr-2.7.6.jar              //HQL解析时使用的包

lib\required\javassist-3.9.0.GA.jar       //字节码类库,类似于cglib

lib\required\commons-collections-3.1.jar  //对集合类型支持包,前边测试时已经提供过了,无需再拷贝该包了

lib\required\dom4j-1.6.1.jar            //xml解析包,用于解析配置使用

lib\required\jta-1.1.jar                 //JTA事务支持包

lib\jpa\hibernate-jpa-2.0-api-1.0.0.Final.jar //用于支持JPA

下载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:

java代码:
1
2
3
4
5
6
package cn.javass.spring.chapter7;
public class UserModel {
     private int id;
     private String myName;
     //省略getter和setter
}

3、Hibernate映射定义(chapter8/hbm/user.hbm.xml),定义对象和数据库之间的映射:

java代码:
1
2
3
4
5
6
7
8
9
10
<?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):

java代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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:

java代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
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对象进行创建和删除表:

java代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
@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对象进行持久化数据:

java代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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);
     }
}
java代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
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的使用:

java代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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实现:

java代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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中添加如下配置:

java代码:
1
2
3
4
<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):

java代码:
1
2
3
4
5
6
7
8
9
10
11
12
@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指定数据库列映射;
java代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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属性指定注解模型来定义映射元数据;

java代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
<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 :

java代码:
1
2
3
<bean id= "hibernateTemplate" class = "org.springframework.orm.hibernate3.HibernateTemplate" >
     <property name= "sessionFactory" ref= "sessionFactory" />
</bean>

3、最后进行CURD测试吧:

java代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@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方式简单许多,而且支持注解方式配置映射元数据,从而减少映射定义配置文件数量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值