《Spring3實戰》摘要(5-2)Spring中使用Hibernate

5.4 在 Spring 中集成Hibernate

隨着應用程序變得越來越複雜,對持久化的需求也變得越來越複雜。我們需要將對象的屬性映射到數據庫的裂傷,並且需要自動生成語句和查詢,這樣我們就能從無休止的問號字符串中解脫出來。我們還需要一些更復雜的特性:

  • 延遲加載(Lazy loading):隨着對象關係變得越來越複雜,有時候我們並不希望立即獲取完整的對象間關係。藉助於延遲加載,我們可以只抓取需要的數據,減少查詢無用數據的開銷。
  • 預先抓取(Eager fetching):這與延遲加載是相對的。藉助於預先抓取,我們可以使用一個查詢獲取完整的關聯對象。預先抓取功能可以在一個操作中將對象及其關聯的對象數據全部從數據庫中提取出來,這節省了多次查詢的成本。
  • 級聯(Cascading):有時,更改數據庫中的表會勇士修改其他表。如訂購單的例子,當刪除 Order(訂貨單表) 對象時,我們希望同時在數據庫中刪除關聯的 LineItem(訂貨單對應的貨品明細) 。

一些可用的框架提供了這樣的服務。這些服務的通用名稱是對象/關係(object-relational mapping,ORM)。

Spring 對多個持久化框架都提供了支持,包括 Hibernate、IBATIS(於2010年6月16號被谷歌託管,改名爲MyBatis。是一個基於SQL映射支持Java和·NET的持久層框架)、Java數據對象(Java Data Objects,JDO)以及 Java 持久化 API。

Spring 對 ORM 框架的支持提供了與這些框架的集成點以及一些附加的服務,如下所示

  • Spring 聲明式事務的集成支持;
  • 透明的異常處理;
  • 線程安全的、輕量級的模板類;
  • DAO 支持類;
  • 資源管理。

5.4.1 Hibernate 概覽

Spring 對 Hibernate 的支持也提供了類似的模板類來抽象 Hibernate 的持久化功能。

以前,在 Spring 應用程序中使用 Hibernate 是通過 HibernateTemplate 進行的。與 JDBC 對等的對象很類似。

HibernateTemplate 簡化了使用 Hibernate 的繁瑣工作,這是通過捕獲 Hibernate 特定的異常,然後將其轉換爲 Spring 的非檢查型數據訪問異常並重新拋出而實現的。

HibernateTemplate 的不足之處在於存在一定程度的侵入性。不管是直接使用還是通過 HibernateDAOSupport 時,DAO 類就會與 Spring API 產生了耦合。

儘管 HibernateTemplate 還存在,但是這已經不是使用 Hibernate 的最佳方式了。Hibernate 3 所引入了上下文 Session (Contextual session)的方案,這是 Hibernate 本身所提供的保證每個事務使用同一個 session 的方案,因此沒有必要再使用 HibernateTemplate 來保證這一行爲了。這種方式能夠讓你的 DAO 類不包含特定的 Spring 代碼。

5.4.2 聲明 Hibernate 的 Session 工廠

使用 Hibernate 的主要接口是 org.hibernate.Session。 該Session接口提供了基本的數據訪問功能。應用程序的 DAO 通過 Session 接口能夠滿足所有的持久化需求。

獲取 Hibernate Session 對象的標準方式是藉助於 Hibernate 的 SessionFactory 接口的實現類。除了一些其他的任務,SessionFactory 主要負責 Hibernate Session 的打開、關閉以及管理。

在 Spring 中,我們要通過 Spring 的某一個 Hibernate Session 工廠 Bean 來獲取 Hibernate 的 SessionFactory 。

注:需要添加 spring-orm.jar

在配置 Hibernate Session 工廠 Bean 的時候,我們需要確定持久化域對象是通過 XML 文件還是通過註解來進行配置的。如果選擇在 XML 中定義對象與數據庫之間的映射,那麼需要在 Spring 中配置 LocalSessionFactoryBean

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="mappingResources">
        <list>
            <value>Spitter.hbm.xml</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="dialect">org.hibernate.dialect.H2Dialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
        </props>
    </property>
</bean>

如果你更傾向於使用註解的方式來定義持久化,那需要使用 AnnotationSessionFactoryBean 來代替 LocalSessionFactoryBean:

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <!-- 配置需要掃描 JPA 註解的包 -->
    <property name="packagesToScan" value="com.habuma.spitter.domain" />

    <!-- 需要掃描的包郵多個時的配置
    <property name="packagesToScan">
        <list>
            <value>xx.xxx.xxx</value>
        </list>
    </property>
    -->

    <!-- 還可以通過使用 annotatedClasses 屬性來將應用程序中所有的持久化類以全限定名的方式明確列出
    <property name="annotatedClasses">
        <list>
            <value>xxx.xxx.xxx.Spitter</value>
        </list>
    </property>
     -->
    <property name="hibernateProperties">
        <props>
            <prop key="dialect">org.hibernate.dialect.H2Dialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
        </props>
    </property>
</bean>

5.4.3 構建不依賴於 Spring 的 Hibernate 代碼

import org.hibernate.SessionFactory;
import org.hibernate.classic.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.spring.springdemo.spitter.entity.Spitter;

@Repository
public class HibernateSpitterDao implements SpitterDAO {

    private SessionFactory sessionFactory;

    @Autowired
    public HibernateSpitterDao(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    // 從 SessionFactory 中獲取當前的 Session
    private Session currentSession(){
        return sessionFactory.getCurrentSession();
    }

    @Override
    public void addSpitter(Spitter spitter) {
        currentSession().save(spitter);
    }

    @Override
    public Spitter getSpitterById(long id) {
        return (Spitter) currentSession().get(Spitter.class, id);
    }
}

@Repository 在上面的示例代碼中,除了幫助簡化 XML 配置以外,@Repository 還可以輔助 PersistenceExceptionTranslationPostprocessor Bean。

PersistenceExceptionTranslationPostprocessor 是一個 Bean 的後置處理程序,它會在所有擁有 @Repository 註解的類上添加一個通知器(advisor),這樣就會捕獲任何平臺相關的異常並以 Spring 的非檢查型數據訪問異常的形式重新拋出。

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostprocessor" />

5.5 Spring 與 Java 持久化 API(略)

Java 持久化 API(Java Persistence API ,JPA)誕生在 EJB 2 實體 Bean 的廢墟之上,併成爲下一代 Java 持久化標準。JPA 是基於 POJO 的持久化機制,它從 Hibernate 和 Java 數據對象(Java Data Object,JDO)上借鑑了很多理念並加入了 Java 5 註解的特性。

5.5.1 配置實體管理器工廠

簡單來說,基於 JPA 的應用程序使用 EntityManagerFactory 的實現類來獲取 EntityManager 實例。JPA 定義了兩種類型的實體管理器:

  • 應用程序管理類型(Application-managed):當應用程序向實體管理器工廠直接請求實體管理器時,工廠會創建一個實體管理器。在這種模式下,程序要負責打開或關閉實體管理器並在事務中對其進行控制。這種方式的實體管理器適合不運行在 Java EE 容器中的對立應用程序。
  • 容器管理類型(Container-managed):實體管理器由 Java EE創建和管理。應用程序個人呢不讓你不與實體管理器工廠打交道。相反,實體管理器直接通過注入或 JNDI 來獲取。容器負責配置實體管理器工廠。這種情況下會希望在 persistence.xml 指定的配置之外保持一些自己對 JPA 的控制。

。。。。下面的暫時略過。。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章