Spring整合ORM技术 -- 集成Hibernate


原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。 http://aku28907.blog.51cto.com/5668513/1825541

1、Spring整合ORM方案的好处:

  • 方便基础设施的搭建。不同的ORM技术都有一套自己的方案以初始化框架、搭建基础设施等。在搭建基础设施中,数据源是不可或缺的资源,不同的ORM框架的实现方式各不相同。Spring针对不同的ORM框架,采用相同的方式配置数据源,并为不同的ORM框架提供相同的FactoryBean,用以初始化ORM框架的基础设施,可以把它们当成普通Bean对待。

  • 异常封装。Spring能够转化各种ORM框架抛出的异常,将ORM框架专有的或检查型异常转换为SpringDAO异常体系中的标准异常。这样用户就可以有选择地在适当的地方处理感兴趣的异常,忽略不可恢复的异常。

  • 统一的事务管理。通过使用基于SpringDAO模板编程风格,甚至使用原生的ORM框架的API,只要遵循Spring所提出的少量编程要求,就可以使用Spring提供的事务管理功能。Spring为不同的ORM框架提供了对应的事务管理器,可用声明式事务管理,并且透明地实现本地事务管理到全局JTA事务管理的切换。

  • 允许混合使用多个ORM框架。Spring在DAO层异常、事务、资源等高级层次建立了抽象,可以让业务层对DAO具体实现的技术不敏感。这样开发者就可以在底层选用合适的实现方式,甚至可以混合使用多种ORM,一般的CRUD使用Hibernate,而数据查询使用iBatis或SpringJDBC。

  • 方便单元测试。Spring容器使得替换不同的实现和配置方式变得很简单,这有利于单元测试

2、Spring整合Hibernate步骤

    2.1 配置SessionFactory(可自动完成)

        使用Hibernate框架的第一个工作是编写Hibernate的配置文件,接着使用这些配置文件实例化SessionFactory,创建好Hibernate的基础设施。Spring为创建SessionFactory提供了FactoryBean工厂类:org.springframework.orm.hibernate3.LocalSessionFactoryBean,通过一些必要的配置,即可或缺一个SessionFactoryBean。

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<? xml  version = "1.0"  encoding = "UTF-8" ?>
< beans  xmlns = "http://www.springframework.org/schema/beans"
  xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:p = "http://www.springframework.org/schema/p"
  xmlns:context = "http://www.springframework.org/schema/context"
  xmlns:aop = "http://www.springframework.org/schema/aop" 
  xmlns:tx = "http://www.springframework.org/schema/tx"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.1.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
     http://www.springframework.org/schema/tx
     http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
     
     < context:component-scan  base-package = "org.worm.biz.springmvc" />
     < context:property-placeholder  location = "classpath:jdbc.properties" />
     < bean  id = "dataSource"  class = "org.apache.commons.dbcp.BasicDataSource"
      destroy-method = "close"
      p:driverClassName = "${jdbc.driverClassName}"
      p:url = "${jdbc.url}"
      p:username = "${jdbc.username}"
      p:password = "${jdbc.password}"/>
     <!-- 也可以使用p:mappingDirectoryLocations来指定多个放置Hibernate映入文件的目录 --> 
     < bean  id = "sessionFactory"  class = "org.springframework.orm.hibernate3.LocalSessionFactoryBean"
      p:dataSource-ref = "dataSource"
      p:mappingLocations = "classpath:org/worm/biz/springmvc/dao/*.hbm.xml" >
      <!-- 指定Hibernate配置文件 -->
      < property  name = "hibernateProperties" >
       < props >
        < prop  key = "hibernate.dialect" >org.hibernate.dialect.Oracle10gDialect</ prop >
        < prop  key = "hibernate.show_sql" >true</ prop >
        < prop  key = "hibernate.formate_sql" >true</ prop >
       </ props >
      </ property
     </ bean >
     
     <!-- 配置HibernateTemplate Bean -->
     < bean  id = "hibernateTemplate"  class = "org.springframework.orm.hibernate3.HibernateTemplate"
      p:sessionFactory-ref = "sessionFactory" />
     <!-- 配置Hibernate事务管理 -->
     < bean  id = "transactionManager"  class = "org.springframework.orm.hibernate3.HibernateTransactionManager"
      p:sessionFactory-ref = "sessionFactory" />
     < tx:annotation-driven  transaction-manager = "transactionManager" />
     </ beans >

    2.2、使用HibernateTemplate

        基于模板类使用Hibernate是最简单的方式,它可以在不牺牲Hibernate强大功能的情况下,以一种更简洁的方式使用Hibernate,极大地降低了Hibernate的使用难度。

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package  org.worm.biz.springmvc.dao.hibernate;
import  java.util.List;
public  interface  IBaseDao<T> {
  /**
   * 保存实体对象
   * @param t 实体对象
   * */
  public  void  addEntity(T t);
  
  /**
   * 更新实体对象
   * @param t 实体对象
   * */
  public   void  updateEntity(T t);
  
  /**
   * 获取实体对象
   * @param serialNo 主键
   * */
  public   T getEntity(String serialNo,T t);
  
  /**
   * 获取实体对象集
   * @param hql 查询语句
   * @param params 查询条件
   * */
  public   List<T> getEntities(String hql,Object[] params);
  
  /**
   * 获取实体对象集
   * */
  public   List<T> getEntitiesByExample(T t);
}
 
package  org.worm.biz.springmvc.dao.hibernate;
import  java.lang.reflect.ParameterizedType;
import  java.lang.reflect.Type;
import  java.util.List;
import  org.springframework.beans.factory.annotation.Autowired;
import  org.springframework.orm.hibernate3.HibernateTemplate;
public  class  BaseDao<T>  implements  IBaseDao<T> {
  private  Class entityClass; //Dao的泛型类型,即子类所指定的T所对应的类型
  
  public  BaseDao() {
   Type genType = getClass().getGenericSuperclass();
   Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
   entityClass = (Class) params[ 0 ];
  }
  @Autowired
  private  HibernateTemplate hibernateTemplate;
  public  HibernateTemplate getHibernateTemplate() {
   return  hibernateTemplate;
  }
  public  void  setHibernateTemplate(HibernateTemplate hibernateTemplate) {
   this .hibernateTemplate = hibernateTemplate;
  }
  
  @Override
  public  void  addEntity(T t) {
   // TODO Auto-generated method stub
   getHibernateTemplate().save(t);
  }
  @Override
  public   void  updateEntity(T t) {
   // TODO Auto-generated method stub
   getHibernateTemplate().update(t);
  }
  @Override
  public   T getEntity(String serialNo) {
   // TODO Auto-generated method stub
   return  (T) getHibernateTemplate().get(entityClass, Integer.valueOf(serialNo));
  }
  @Override
  public   List<T> getEntities(String hql, Object[] params) {
   // TODO Auto-generated method stub
   return  (List<T>) getHibernateTemplate().find(hql, params);
  }
  @Override
  public   List<T> getEntitiesByExample(T t) {
   // TODO Auto-generated method stub
   return  getHibernateTemplate().findByExample(t);
  }
}
 
package  org.worm.biz.springmvc.dao.hibernate;
import  org.springframework.stereotype.Repository;
import  org.worm.biz.springmvc.dao.User;
@Repository
public  class  UserDao  extends  BaseDao<User>{
  //添加自身独有的业务
}

    2.3、使用Hibernate原生Hibernate API

        使用Hibernate原生API与在Spring中使用HibernateTemplate中使用和事务绑定的Session相同

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package  org.worm.biz.springmvc.dao.hibernate;
import  java.util.List;
import  org.hibernate.SessionFactory;
import  org.springframework.beans.factory.annotation.Autowired;
import  org.worm.biz.springmvc.dao.User;
public  class  BaseDao  implements  IBaseDao<User> {
// @Autowired
// private HibernateTemplate hibernateTemplate;
//
// public HibernateTemplate getHibernateTemplate() {
//  return hibernateTemplate;
// }
//
// public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
//  this.hibernateTemplate = hibernateTemplate;
// }
  @Autowired
  private  SessionFactory sessionFactory;
  
  @Override
  public  void  addEntity(User t) {
   // TODO Auto-generated method stub
//  getHibernateTemplate().save(t);
   sessionFactory.getCurrentSession().save(t);
  }
  @Override
  public   void  updateEntity(User t) {
   // TODO Auto-generated method stub
//  getHibernateTemplate().update(t);
   sessionFactory.getCurrentSession().update(t);
  }
  @Override
  public   User getEntity(String serialNo, User t) {
   // TODO Auto-generated method stub
//  return (User) getHibernateTemplate().get(t.getClass(), Integer.valueOf(serialNo));
   return  (User) sessionFactory.getCurrentSession().get(t.getClass(), Integer.valueOf(serialNo));
  }
  @Override
  public   List<User> getEntities(String hql, Object[] params) {
   // TODO Auto-generated method stub
//  return (List<User>) getHibernateTemplate().find(hql, params);
   return  null ;
  }
  @Override
  public   List<User> getEntitiesByExample(User t) {
   // TODO Auto-generated method stub
//  return getHibernateTemplate().findByExample(t);
   return  null ;
  }
}

    2.4、使用注解配置Entity

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
32
33
34
35
36
37
38
39
40
41
42
43
44
package  org.worm.biz.springmvc.dao;
import  javax.persistence.*;
 
@Entity
//@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Table (name =  "t_user" )
public  class  User{
     @Id
     @GeneratedValue (strategy = GenerationType.IDENTITY)
     @Column (name =  "user_no" )
     protected  int  userId;
     @Column (name =  "user_nick_name" )
     protected  String userName;
     protected  String password;
     
     @Column (name =  "user_age" )
     protected  String userAge;
     
     public  int  getUserId() {
         return  userId;
     }
     public  void  setUserId( int  userId) {
         this .userId = userId;
     }
     public  String getUserName() {
         return  userName;
     }
     public  void  setUserName(String userName) {
         this .userName = userName;
     }
     public  String getPassword() {
         return  password;
     }
     public  void  setPassword(String password) {
         this .password = password;
     }
  public  String getUserAge() {
   return  userAge;
  }
  public  void  setUserAge(String userAge) {
   this .userAge = userAge;
  }
     
}

    Hibernate通过AnnotationConfiguration的addAnnotatedClass()方法加载使用JPA注解的实体类,获取映射的元数据信息, 并在此基础上创建SessionFactory实例。AnnotationSessionFactoryBean扩展了LocalSessionFactoryBean类,增强的功能是:可以根据实体类的注解获取ORM的配置信息。也允许混合使用XML配置和注解配置对象关系映射,Hibernate内部自动整合这些元数据信息,不会产生冲突。Spring为了可以通过扫描方式加载带注解的实体类,提供了一个好用的packagesToScan属性,可以指定一系列的包名,Spring将扫描并加载这些包(包含子包)路径的所有带注解实体类。

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<? xml  version = "1.0"  encoding = "UTF-8" ?>
< beans  xmlns = "http://www.springframework.org/schema/beans"
  xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:p = "http://www.springframework.org/schema/p"
  xmlns:context = "http://www.springframework.org/schema/context"
  xmlns:aop = "http://www.springframework.org/schema/aop" 
  xmlns:tx = "http://www.springframework.org/schema/tx"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.1.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
     http://www.springframework.org/schema/tx
     http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
     
     < context:component-scan  base-package = "org.worm.biz.springmvc" />
     < context:property-placeholder  location = "classpath:jdbc.properties" />
     < bean  id = "dataSource"  class = "org.apache.commons.dbcp.BasicDataSource"
      destroy-method = "close"
      p:driverClassName = "${jdbc.driverClassName}"
      p:url = "${jdbc.url}"
      p:username = "${jdbc.username}"
      p:password = "${jdbc.password}"/>
     <!-- 也可以使用p:mappingDirectoryLocations来指定多个放置Hibernate映入文件的目录 --> 
<!--     <bean id="sessionFactory" class = "org.springframework.orm.hibernate3.LocalSessionFactoryBean" -->
<!--      p:dataSource-ref = "dataSource" -->
<!--      p:mappingLocations="classpath:org/worm/biz/springmvc/dao/*.hbm.xml"> -->
<!--      <property name="hibernateProperties"> -->
<!--       <props> -->
<!--        <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> -->
<!--        <prop key="hibernate.show_sql">true</prop> -->
<!--        <prop key="hibernate.formate_sql">true</prop> -->
<!--       </props> -->
<!--      </property>  -->
<!--     </bean> -->
     <!-- 带注解实体类 -->
     < bean  id = "sessionFactory_1"  class = "org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
      p:dataSource-ref = "dataSource">
      <!-- 通过扫描方式加载带注解的实体类 -->
      < property  name = "packagesToScan"  value = "org.worm.biz.springmvc.dao" />
      <!-- 指定Hibernate配置文件 -->
      < property  name = "hibernateProperties" >
       < props >
        < prop  key = "hibernate.dialect" >org.hibernate.dialect.Oracle10gDialect</ prop >
        < prop  key = "hibernate.show_sql" >true</ prop >
        < prop  key = "hibernate.formate_sql" >true</ prop >
       </ props >
      </ property
     </ bean >
     <!-- 配置HibernateTemplate Bean -->
     < bean  id = "hibernateTemplate"  class = "org.springframework.orm.hibernate3.HibernateTemplate"
      p:sessionFactory-ref = "sessionFactory" />
     <!-- 配置Hibernate事务管理 -->
     < bean  id = "transactionManager"  class = "org.springframework.orm.hibernate3.HibernateTransactionManager"
      p:sessionFactory-ref = "sessionFactory" />
     < tx:annotation-driven  transaction-manager = "transactionManager" />
     </ beans >

    2.5 统一使用事务管理,详情配置请见2.2

3、延迟加载问题

    Hibernate允许对关联对象、属性进行延迟加载,但是必须保证延迟加载的操作限于同一个Hibernate Session范围之内进行。如果Service层返回一个启用了延迟加载功能领域对象给Web层,当Web层访问到那些需要延迟加载的数据时,由于加载领域对象的Hibernate Session已经关闭,将会导致延迟加载数据异常。因此Spring专门提供了一个OpenSessionInViewFilter过滤器,它的主要功能是使每个请求过程中绑定一个Hibernate Session,即使最初的事务已经完成了,可以在Web层进行延迟加载的操作。注意:对小型系统来说,使用OpenSessionInViewFilter确实可以降低延迟加载所引发的各种问题,使Service层代码更易开发和维护,但是对大型且高并发的应用来说,强烈建议不要使用OpenSessionInViewFilter。因为OpenSessionInViewFilter会让每个Web请求线程都绑定一个Hibernate的Session。知道Web请求处理时才会释放。这极大的影响了系统新能。

4、DAO层设计

    为了增加代码复用率,强烈建议使用接口、基类和泛型来定义。详情见2.2.基类BaseDao<T>通过泛型方式允许子类Dao指定操作的实体类,以便简化常用的数据操作方法。同时,在BaseDao注入了一个HibernateTemplate,这样子类只要打上@Repository的注解就自然拥有HibernateTemplate成员变量了,无须各自声明。BaseDao的构造方法通过Java反射机制自动解析出子类T锁对应的类型,以便HibernateTemplate直接利用这个信息进行数据访问操作。

5、查询接口方法的设计

    DAO层除了CRUD的数据操作之外,另外一个重要的操作就是根据查询条件执行数据查询,所有ORM框架都允许用户动态绑定参数确定查询条件。查询条件的数目往往是不固定的。因此实体DAO定义带参数的查询方法一般有:

  • 每一个条件项参数对应一个入参。List<T> findOrder(String hql,Date starttime,Date endtime,int deptId);这种方法优点是含义清晰,可读性强,内部逻辑简单,但是接口稳定性差,并且如果查询条件项过多,整个实体DAO类会显得很臃肿笨重。

  • 使用数组传递条件项参数。List<T> findOrder(String hql,Object[] params);这种方法的确定是可读性不强,调用者往往需要通过查看该接口的Javadoc才能正确使用。

  • 使用JDK5.0的不定参数。List<T> findOrder(String hql,Object... params);

  • 将查询条件项参数封装成对象。List<T> findOrder(String hql,OrderObject param);OrderObject查询条件对象封装了hql查询语句可能会用到的条件项参数,在查询方法内部,开发者必须判断查询条件对象的属性并正确绑定条件项参数。确定是会造成类数目的膨胀,有事甚至一个实体DAO需要对应多个查询条件参数类。

  • 使用Map传递条件项参数。List<T> findOrder(String hql,Map params)使用这样方式,接口方法签名可以在条件项发生变化的情况下保持稳定,同事通过键指定条件项参数名,这在一定程度上解决了接口的健壮性。

6、总结

    Spring为其所支持的ORM框架提供了方面易用的FactoryBean,用以创建ORM框架的基础设施。Spring通过模板类在不损失框架功能的情况下大大降低了使用这些ORM技术的难度。此外Spring允许用户使用原生的API来构造DAO。使用原生API时,Spring能够保证用户获取到事务绑定的资源,Spring的事务管理机制同样有效。

    Spring对Hibernate所提供的支持应该是最丰富的。

本文出自 “阿酷博客源” 博客,请务必保留此出处http://aku28907.blog.51cto.com/5668513/1825541

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值