`
black_angle
  • 浏览: 48193 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

spring 和hibernate的整合

阅读更多

      在当前的整合过程中,最常见的整合就是利用spring的HibernateTemplate或者是HibernateDaoSupport ,但是这都对底层的hibernater产生了侵入性,如果利用hibernate3的一个新的特性:“带上下文环境的Session”。 这与Spring中每个Hibernate的 Session 与事务同步的功能大致相同。即:sessionFactory.getCurrentSession()。他可以获取到在spring中配置的事务管理器中产生的session,这样就可以利用spring的事务管理 ,也可以把spring对hibernate的侵入性降到最低。

    整个程序的框架是:使用了Service + DAO的模式,并将Service放在事务管理器中,采用声明式的事务管理,而DAO仅仅注入给Service,不进行事务管理。当时的理由是Service用来控制业务流程,应该由它决定事务的边界,DAO只是功能点,无需过问事务。

配置:

<!-- 读取 hibernate.cfg.xml配置文件 并产生sessionFactory对象,不采用在application.xml中

配置数据源什么的就是为了减少spring和hibernate的耦合度-->

<bean id="sessionFactory"
  class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
  <property name="configLocation"
   value="classpath:hibernate.cfg.xml">
  </property>
 </bean>

<!--   原来读取 hibernate.cfg.xml并且产生sessionFactory和利用ThreadLocal保存和获取session的类-->
 <bean id ="hibernateSessionFactory" class="com.mawujun.HibernateSessionFactory">
  <property name="sessionFactory">
   <ref bean="sessionFactory"/>
  </property>
 </bean>

<!-- 继承HibernateTemplate,获取事务管理器中创建的session ,这是另外种方法在不知道sessionFactory.getCurrentSession()。的情况下的折中方法。
   <bean id="baseHibernateDAO1" class="com.mawujun.BaseHibernateDAO1">
     <constructor-arg><ref bean="sessionFactory"/></constructor-arg>
    </bean>
    -->

<!---  BaseHibernateDAO依赖于HibernateSessionFactory,主要是用HibernateSessionFactory.getSession()--->
        <bean id="baseHibernateDAO1" class="com.mawujun.BaseHibernateDAO">
        </bean>

<!--  或直接让BaseHibernateDAO依赖于SessionFactory ,这样更好session 就完全交给spring去控制  -->

  <bean id="baseHibernateDAO1" class="com.mawujun.BaseHibernateDAO2">
   <property name="sessionFactory">
    <ref bean="sessionFactory"/>
   </property>
  </bean>


<!-- dao对象 依赖于BaseHibernateDAO, -->
 <bean id="userdao" class="com.mawujun.TUserDAO">
  <property name="baseHibernateDAO1">
   <ref bean="baseHibernateDAO1"/>
  </property>
 </bean>


 <!-- 日志记录的aop -->
 <bean id="myAdvisor" class="com.mawujun.TestBeforeAdvice">
 </bean>
 <bean id="userDaoPeoxy"
  class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="proxyInterfaces">
   <value>com.mawujun.TUserDAOInter</value>
  </property>
  <property name="target">
   <ref local="userdao" />
  </property>

  <property name="interceptorNames">
   <list>
    <value>myAdvisor</value>
   </list>
  </property>
 </bean>
  <!-- 服务层的配置 -->
 <bean id="service" class="com.mawujun.Service">
  <property name="userDAO">
   <ref local="userdao"/>
  </property>
 </bean>

<!-- 事务管理者 -->
 <bean id="transactionManager"
       class="org.springframework.orm.hibernate3.HibernateTransactionManager">
       <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>
    <bean id="serviceTransPorxy"
           class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
           <property name="transactionManager">
              <ref bean="transactionManager" />
           </property>
           <property name="transactionAttributes">
              <props>
                  <prop key="find*">
                     PROPAGATION_REQUIRED,-java.lang.Exception
                  </prop>
                  <prop key="update*">
                     PROPAGATION_REQUIRED,-java.lang.Exception
                  </prop>
                  <prop key="save*">
                    PROPAGATION_REQUIRED
                  </prop>
              </props>
           </property>
           <property name="proxyInterfaces">
              <list>
                  <value>com.mawujun.Iservice</value>
              </list>
           </property>
           <property name="target">
              <ref bean="service" />
           </property>
       </bean>

总体来说,DAO可以基于Hibernate3的原生API实现,同时,它依旧需要能够参与到Spring的事务管理中。 这对于那些已经对Hibernate非常熟悉的人来说很有吸引力,因为这种方式更加自然。 不过,此时的DAO将抛出HibernateException,因而,如果有必要的话,需要明确地去做由 HibernateException 到Spring的 DataAccessException 的转化。

http://blog.sina.com.cn/s/blog_4a5ca024010005yz.html

另外种实现方法:链接:  http://hi.baidu.com/injava/blog/item/c08eaf3823f99ec3d4622528.html

(完全拷贝 谢谢macaque1101 )

Hibernate与Spring整合后,就可以使用IoC及AOP的功能了,好处不在多言。另外一个好处,就是可以通过使用Spring的HibernateTemplate来简化数据库CRUD代码。然而,正是这个HibernateTemplate,存在着以下的缺点:

一是功能不全,不如Hibernate的储如createQuery()等方法方便、灵活与强大,使用颇受限制;
二是HibernateTemplate中的SessionFacotry封装得太死,且session常常会自动过早关闭,使用上颇多不便;
三是Spring1.2.7实际上只支持Hibernate3.0.5,HibernateTemplate无法使用Hibernate3.1以后新加的功能。

正是由于这三点,使我抵制住了使用HibernateTemplate的诱惑,在将Spring与Hibernate整合后,通过简单的配置,在Spring程序中自由地使用Hibernate3.1.2的功能。这样既可以实现强强联手,又可以在Hibernate新版本出来后,马上进行重新整合,无需等着新版的Spring出来。

在实现上,主要有三点。

一是在Spring的配置文件中,无需定义长长的hibernateTemplate,只需定义sessionFacotry就行了。

例如,设有一"组织DaoImpl",实现了"组织Dao"及"HibernateDao"两个接口。而"组织Service"通过将"组织DaoImpl"封装起来,对外提供相应的数据库功能服务。

public interface HibernateDao {
     public void setSessionFactory(SessionFactory sessionFactory);
}

public interface 组织Dao {
     public void 增加组织(组织 组织);
     public void 删除组织(Long 组织编号);
     public 组织 get组织By名称(String 组织名称);
     ......
}

public class 组织DaoImpl implements 组织Dao, HibernateDao {
     private SessionFactory sessionFactory;

     public void setSessionFactory(SessionFactory sessionFactory) {
         this.sessionFactory = sessionFactory;
     }

     public 组织 get组织By名称(String 组织名称) {
         ......
     }
}

public interface 组织Service {
     public 组织 get组织By名称(String 组织名称);
     ......
}

(实际代码中,组织Service与组织DaoI的接口是一样的)

先在Spring的配置文件中定义"组织Service"与"组织Dao":

     <bean id="组织Service"
         class="com.sarkuya.service.组织ServiceImpl">
         <property name="组织Dao">
             <ref bean="组织Dao" />
         </property>
     </bean>

     <bean id="组织Dao"
         class="com.sarkuya.model.dao.hibernate.组织DaoImpl">
         <property name="sessionFactory">
             <ref bean="sessionFactory" />
         </property>
     </bean>

这一步比较好理解。问题是如何将我们所需的sessionFactory传过来。Hibernate的sessionFactory不是一个可以用构造方法或setter方法就可以直接生成的类,而是需要进行一定的"运算"后才得出的类,典型的形式如:

sessionFactory = new Configuration().buildSessionFactory();

因此,简单地在Spring中如下配置行不通。

     <bean id="sessionFactory"
         class="org.hibernate.SessionFactory">
         <property name="xxx">
             <value>xxx</valu>
         </property>
     </bean>

所幸,Spring提供了一种可定义由工厂方法所产生的bean的方式。

     <bean id="sessionFactory"
         class="com.sarkuya.hibernate.util.HibernateUtil"
        factory-method="getSessionFactory" />

这种方式,当我们需要得到sessionFacotry的bean时,Spring就会从com.sarkuya.hibernate.util.HibernateUtil的getSessionFactory()方法中获得。这种方式,我们最熟悉不过了:

public class HibernateUtil {
     private static final SessionFactory sessionFactory;
    
     static {
         try {
             sybaseSessionFactory = new Configuration()
                 .addClass(com.sarkuya.model.cfg.hibernate.组织.class)
                 .configure("/hibernate_hsql.cfg.xml")
                 .buildSessionFactory();
         } catch (Throwable ex) {
             System.err.println("Initial SessionFactory creation failed." + ex);
             throw new ExceptionInInitializerError(ex);
         }
     }
    
     public static SessionFactory getSessionFactory() {
         return sessionFactory;
     }
}

好了,以上步骤,我们已经成功地将sessionFactory注入组织Dao中,再注入组织Service中,根据测试先行原则,看看如何在TestCase中获取组织Service这个bean。

二,在代码中获取组织Service。

public class 组织ServiceTest extends TestCase {
     private 组织Service 组织Service;

     protected void setUp() throws Exception {
         String[] configLocation = new String[] {
             "/web/WEB-INF/training-service.xml",
             "/web/WEB-INF/training-data.xml"
         };
         ApplicationContext ac = new FileSystemXmlApplicationContext(configLocation);
        组织Service = (组织Service)ac.getBean("组织Service");
     }

     public void testGet组织By名称() {
         System.out.println("get组织By名称");
        
         组织 组织 = 组织Service.增加组织(new 组织("aaa"));
        
         组织 = 组织Service.get组织By名称("aaa");
         assertEquals("aaa", 组织.get名称());
        
         组织 = 组织Service.get组织By名称("abc");
         assertNull(组织);
     }
}

三,组织DaoImpl的代码:

     /*
      * @param 组织名称
      * @return 组织 或者 null
      */
     public 组织 get组织By名称(String 组织名称) {
         Session session = sessionFactory.getCurrentSession();
         session.beginTransaction();                             //Hiberante3.1以后的代码      
        
         组织 组织 = (组织)session.createQuery("from 组织 c where c.名称 = '" + 组织名称   + "'")
             .uniqueResult();
        
         session.getTransaction().commit();
        
         return 组织;
     }

由上可见,Hibernate的核心代码一点未变,从而在与Spring整合的基础上,实现了与Spring的解耦。


 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics