溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Spring整合ORM技術(shù) -- 集成Hibernate

發(fā)布時間:2020-07-04 22:27:23 來源:網(wǎng)絡(luò) 閱讀:1009 作者:kuchensheng 欄目:開發(fā)技術(shù)

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

  • 方便基礎(chǔ)設(shè)施的搭建。不同的ORM技術(shù)都有一套自己的方案以初始化框架、搭建基礎(chǔ)設(shè)施等。在搭建基礎(chǔ)設(shè)施中,數(shù)據(jù)源是不可或缺的資源,不同的ORM框架的實現(xiàn)方式各不相同。Spring針對不同的ORM框架,采用相同的方式配置數(shù)據(jù)源,并為不同的ORM框架提供相同的FactoryBean,用以初始化ORM框架的基礎(chǔ)設(shè)施,可以把它們當(dāng)成普通Bean對待。

  • 異常封裝。Spring能夠轉(zhuǎn)化各種ORM框架拋出的異常,將ORM框架專有的或檢查型異常轉(zhuǎn)換為SpringDAO異常體系中的標(biāo)準(zhǔn)異常。這樣用戶就可以有選擇地在適當(dāng)?shù)牡胤教幚砀信d趣的異常,忽略不可恢復(fù)的異常。

  • 統(tǒng)一的事務(wù)管理。通過使用基于SpringDAO模板編程風(fēng)格,甚至使用原生的ORM框架的API,只要遵循Spring所提出的少量編程要求,就可以使用Spring提供的事務(wù)管理功能。Spring為不同的ORM框架提供了對應(yīng)的事務(wù)管理器,可用聲明式事務(wù)管理,并且透明地實現(xiàn)本地事務(wù)管理到全局JTA事務(wù)管理的切換。

  • 允許混合使用多個ORM框架。Spring在DAO層異常、事務(wù)、資源等高級層次建立了抽象,可以讓業(yè)務(wù)層對DAO具體實現(xiàn)的技術(shù)不敏感。這樣開發(fā)者就可以在底層選用合適的實現(xiàn)方式,甚至可以混合使用多種ORM,一般的CRUD使用Hibernate,而數(shù)據(jù)查詢使用iBatis或SpringJDBC。

  • 方便單元測試。Spring容器使得替換不同的實現(xiàn)和配置方式變得很簡單,這有利于單元測試

2、Spring整合Hibernate步驟

    2.1 配置SessionFactory(可自動完成)

        使用Hibernate框架的第一個工作是編寫Hibernate的配置文件,接著使用這些配置文件實例化SessionFactory,創(chuàng)建好Hibernate的基礎(chǔ)設(shè)施。Spring為創(chuàng)建SessionFactory提供了FactoryBean工廠類:org.springframework.orm.hibernate3.LocalSessionFactoryBean,通過一些必要的配置,即可或缺一個SessionFactoryBean。

<?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事務(wù)管理 -->
    <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強(qiáng)大功能的情況下,以一種更簡潔的方式使用Hibernate,極大地降低了Hibernate的使用難度。

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所對應(yīng)的類型
 
 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>{
 //添加自身獨(dú)有的業(yè)務(wù)
}

    2.3、使用Hibernate原生Hibernate API

        使用Hibernate原生API與在Spring中使用HibernateTemplate中使用和事務(wù)綁定的Session相同

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

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注解的實體類,獲取映射的元數(shù)據(jù)信息, 并在此基礎(chǔ)上創(chuàng)建SessionFactory實例。AnnotationSessionFactoryBean擴(kuò)展了LocalSessionFactoryBean類,增強(qiáng)的功能是:可以根據(jù)實體類的注解獲取ORM的配置信息。也允許混合使用XML配置和注解配置對象關(guān)系映射,Hibernate內(nèi)部自動整合這些元數(shù)據(jù)信息,不會產(chǎn)生沖突。Spring為了可以通過掃描方式加載帶注解的實體類,提供了一個好用的packagesToScan屬性,可以指定一系列的包名,Spring將掃描并加載這些包(包含子包)路徑的所有帶注解實體類。

<?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事務(wù)管理 -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
     p:sessionFactory-ref="sessionFactory"/>
    <tx:annotation-driven transaction-manager="transactionManager"/>
    </beans>

    2.5 統(tǒng)一使用事務(wù)管理,詳情配置請見2.2

3、延遲加載問題

    Hibernate允許對關(guān)聯(lián)對象、屬性進(jìn)行延遲加載,但是必須保證延遲加載的操作限于同一個Hibernate Session范圍之內(nèi)進(jìn)行。如果Service層返回一個啟用了延遲加載功能領(lǐng)域?qū)ο蠼oWeb層,當(dāng)Web層訪問到那些需要延遲加載的數(shù)據(jù)時,由于加載領(lǐng)域?qū)ο蟮腍ibernate Session已經(jīng)關(guān)閉,將會導(dǎo)致延遲加載數(shù)據(jù)異常。因此Spring專門提供了一個OpenSessionInViewFilter過濾器,它的主要功能是使每個請求過程中綁定一個Hibernate Session,即使最初的事務(wù)已經(jīng)完成了,可以在Web層進(jìn)行延遲加載的操作。注意:對小型系統(tǒng)來說,使用OpenSessionInViewFilter確實可以降低延遲加載所引發(fā)的各種問題,使Service層代碼更易開發(fā)和維護(hù),但是對大型且高并發(fā)的應(yīng)用來說,強(qiáng)烈建議不要使用OpenSessionInViewFilter。因為OpenSessionInViewFilter會讓每個Web請求線程都綁定一個Hibernate的Session。知道Web請求處理時才會釋放。這極大的影響了系統(tǒng)新能。

4、DAO層設(shè)計

    為了增加代碼復(fù)用率,強(qiáng)烈建議使用接口、基類和泛型來定義。詳情見2.2.基類BaseDao<T>通過泛型方式允許子類Dao指定操作的實體類,以便簡化常用的數(shù)據(jù)操作方法。同時,在BaseDao注入了一個HibernateTemplate,這樣子類只要打上@Repository的注解就自然擁有HibernateTemplate成員變量了,無須各自聲明。BaseDao的構(gòu)造方法通過Java反射機(jī)制自動解析出子類T鎖對應(yīng)的類型,以便HibernateTemplate直接利用這個信息進(jìn)行數(shù)據(jù)訪問操作。

5、查詢接口方法的設(shè)計

    DAO層除了CRUD的數(shù)據(jù)操作之外,另外一個重要的操作就是根據(jù)查詢條件執(zhí)行數(shù)據(jù)查詢,所有ORM框架都允許用戶動態(tài)綁定參數(shù)確定查詢條件。查詢條件的數(shù)目往往是不固定的。因此實體DAO定義帶參數(shù)的查詢方法一般有:

  • 每一個條件項參數(shù)對應(yīng)一個入?yún)ⅰist<T> findOrder(String hql,Date starttime,Date endtime,int deptId);這種方法優(yōu)點(diǎn)是含義清晰,可讀性強(qiáng),內(nèi)部邏輯簡單,但是接口穩(wěn)定性差,并且如果查詢條件項過多,整個實體DAO類會顯得很臃腫笨重。

  • 使用數(shù)組傳遞條件項參數(shù)。List<T> findOrder(String hql,Object[] params);這種方法的確定是可讀性不強(qiáng),調(diào)用者往往需要通過查看該接口的Javadoc才能正確使用。

  • 使用JDK5.0的不定參數(shù)。List<T> findOrder(String hql,Object... params);

  • 將查詢條件項參數(shù)封裝成對象。List<T> findOrder(String hql,OrderObject param);OrderObject查詢條件對象封裝了hql查詢語句可能會用到的條件項參數(shù),在查詢方法內(nèi)部,開發(fā)者必須判斷查詢條件對象的屬性并正確綁定條件項參數(shù)。確定是會造成類數(shù)目的膨脹,有事甚至一個實體DAO需要對應(yīng)多個查詢條件參數(shù)類。

  • 使用Map傳遞條件項參數(shù)。List<T> findOrder(String hql,Map params)使用這樣方式,接口方法簽名可以在條件項發(fā)生變化的情況下保持穩(wěn)定,同事通過鍵指定條件項參數(shù)名,這在一定程度上解決了接口的健壯性。

6、總結(jié)

    Spring為其所支持的ORM框架提供了方面易用的FactoryBean,用以創(chuàng)建ORM框架的基礎(chǔ)設(shè)施。Spring通過模板類在不損失框架功能的情況下大大降低了使用這些ORM技術(shù)的難度。此外Spring允許用戶使用原生的API來構(gòu)造DAO。使用原生API時,Spring能夠保證用戶獲取到事務(wù)綁定的資源,Spring的事務(wù)管理機(jī)制同樣有效。

    Spring對Hibernate所提供的支持應(yīng)該是最豐富的。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI