首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Hibernate 與 Spring 整合:解決延遲載入與 DAO 模式的最佳實踐

     編輯:Java 相關知識

問題:延遲載入需要開啟的 Session

Hibernate 的延遲載入(Lazy Loading)在存取關聯集合或代理物件時,需要有效的 Session。若採用 DAO 模式將持久層邏輯(含 Session 開關)封裝於 DAO 實作類中,Service 層呼叫 DAO 後 Session 已關閉,導致後續存取關聯屬性時拋出 LazyInitializationException。

Spring 解決方案:Open Session In View

Spring 提供兩種機制將 Session 生命週期延伸至 View 渲染完成:

  • OpenSessionInViewFilter:Servlet Filter,在 web.xml 設定,於 Spring 容器之前啟動。
  • OpenSessionInViewInterceptor:Spring MVC Interceptor,在 Spring 容器內運作,於 *-servlet.xml 設定。

兩者功能相同:請求進入時綁定 Session 至當前執行緒,View 完成後關閉 Session,期間 DAO 可透明使用延遲載入。

Filter 設定範例 (web.xml)

<filter>
  <filter-name>hibernateFilter</filter-name>
  <filter-class>org.springframework.orm.hibernate.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>hibernateFilter</filter-name>
  <url-pattern>*.spring</url-pattern>
</filter-mapping>

Interceptor 設定範例 (applicationContext.xml)

<beans>
  <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="interceptors">
      <list><ref bean="openSessionInViewInterceptor"/></list>
    </property>
    <property name="mappings">...</property>
  </bean>

  <bean name="openSessionInViewInterceptor"
        class="org.springframework.orm.hibernate.support.OpenSessionInViewInterceptor">
    <property name="sessionFactory"><ref bean="sessionFactory"/></property>
  </bean>
</beans>

DAO 實作簡化:HibernateTemplate

Spring 的 HibernateDaoSupport 提供 getHibernateTemplate(),DAO 僅需繼承該類別即可簡潔操作:

public class HibernateProductDAO extends HibernateDaoSupport implements ProductDAO {
    public Product getProduct(Integer id) {
        return (Product) getHibernateTemplate().load(Product.class, id);
    }
    public Integer saveProduct(Product p) {
        return (Integer) getHibernateTemplate().save(p);
    }
    public void updateProduct(Product p) {
        getHibernateTemplate().update(p);
    }
}

Service 層延遲載入:HibernateInterceptor

若不想將 Session 洩漏至 Web 層,可在 Service 層使用 AOP 攔截器管理 Session:

<beans>
  <bean id="hibernateInterceptor"
        class="org.springframework.orm.hibernate.HibernateInterceptor">
    <property name="sessionFactory"><ref bean="sessionFactory"/></property>
  </bean>

  <bean id="businessObjectTarget" class="com.acompany.BusinessObjectImpl">
    <property name="someDAO"><ref bean="someDAO"/></property>
  </bean>

  <bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target"><ref bean="businessObjectTarget"/></property>
    <property name="proxyInterfaces"><value>com.acompany.BusinessObject</value></property>
    <property name="interceptorNames">
      <list><value>hibernateInterceptor</value></list>
    </property>
  </bean>
</beans>

呼叫 businessObject 代理時,攔截器自動開啟/關閉 Session,Service 方法可透明使用延遲載入。

單元測試中的延遲載入支援

繼承 TestCase 並在 setUp()/tearDown() 手動綁定/解除 Session:

public abstract class MyLazyTestCase extends TestCase {
    public void setUp() throws Exception {
        super.setUp();
        SessionFactory sf = (SessionFactory) getBean("sessionFactory");
        Session s = sf.openSession();
        TransactionSynchronizationManager.bindResource(sf, new SessionHolder(s));
    }
    public void tearDown() throws Exception {
        super.tearDown();
        SessionFactory sf = (SessionFactory) getBean("sessionFactory");
        SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
        Session s = holder.getSession();
        s.flush();
        TransactionSynchronizationManager.unbindResource(sf);
        SessionFactoryUtils.closeSessionIfNecessary(s, sf);
    }
    protected Object getBean(String name) { /* 從 Spring 容器取得 */ }
}

總結

層級解決方案適用場景
Web/ControllerOpenSessionInViewFilter / Interceptor傳統 MVC,View 需存取領域模型關聯
ServiceHibernateInterceptor (AOP)分層架構,Service 封裝業務邏輯,不洩露持久層細節
測試手動綁定 Session 於 ThreadLocalJUnit 整合測試延遲載入行為

Spring 與 Hibernate 的無縫整合,讓開發者同時擁有「乾淨的分層架構」與「高效能的延遲載入」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved