假設在你的應用中hibernate是通過spring 來管理它的session.如果在你的應用中沒有使用opensessioninviewfilter或者opensessioninviewinterceptor。session會在transaction結束後關閉。
如果你采用了spring的聲明式事務模式,它會對你的被代理對象的每一個方法進行事務包裝(aop的方式)。如下:
<bean id="txproxytemplate" abstract="true"
class="org.springframework.transaction.interceptor.transactionproxyfactorybean">
<property name="transactionmanager" ref="transactionmanager"/>
<property name="transactionattributes">
<props>
<prop key="save*">propagation_required</prop>
<prop key="remove*">propagation_required</prop>
<prop key="*">propagation_required,readonly</prop>
</props>
</property>
</bean>
<bean id="manager" parent="txproxytemplate">
<property name="target">
<bean class="org.appfuse.service.impl.basemanager">
<property name="dao" ref="dao"/>
</bean>
目标類org.appfuse.service.impl.basemanager 的 save *方法的事務類型propagation_required ,remove* 方法的事務類型propagation_required
其他的方法的事務類型是propagation_required,readonly。
是以給你的感覺是調用這個名為“manager”的bean的方法之後session就關掉了。
如果應用中使用了opensessioninviewfilter或者opensessioninviewinterceptor,所有打開的session會被儲存在一個線程變量裡。線上程退出前通過
opensessioninviewfilter或者opensessioninviewinterceptor斷開這些session。 為什麼這麼做?這主要是為了實作hibernate的延遲加載功能。基于一個請求
一個hibernate session的原則。
spring中對opensessioninviewfilter的描述如下:
它是一個servlet2.3過濾器,用來把一個hibernate session和一次完整的請求過程對應的線程相綁定。目的是為了實作"open session in view"的模式。
例如: 它允許在事務送出之後延遲加載顯示所需要的對象。
這個過濾器和 hibernateinterceptor 有點類似:它是通過線程實作的。無論是沒有事務的應用,還是有業務層事務的應用(通過hibernatetransactionmanager 或
jtatransactionmanager的方式實作)它都适用。在後一種情況下,事務會自動采用由這個filter綁定的session來進行相關的操作以及根據實際情況完成送出操作。
警告: 如果在你的應用中,一次請求的過程中使用了單一的一個hibernate session,在這種情況下,采用這個filter會産生一些以前沒遇到的問題。特别需要注意的是通過
hibernate session重新組織持久化對象之間關系的相關操作需要在請求的最開始進行。以免與已經加載的相同對象發生沖突。
或者,我們可以通過指定"singlesession"="false"的方式把這個過濾器調到延期關閉模式。這樣在一次請求的過程中不會使用一個單一的session.每一次資料通路或事務相關
操作都使用屬于它自己的session(有點像不使用open session in view).這些session都被注冊成延遲關閉模式,即使是在這一次的請求中它相關操作已經完成。
"一次請求一個session" 對于一級緩存而言很有效,但是這樣可以帶來副作用。例如在saveorupdate的時候或事物復原之後,雖然它和“no open session in view”同樣安全。
但是它卻允許延遲加載。
它會在spring的web應用的上下文根中查找session工廠。它也支援通過在web.xml中定義的“sessionfactorybeanname”的init-param元素 指定的session工廠對應的bean的
名字來查找session工廠。預設的bean的名字是"sessionfactory".他通過每一次請求查找一次sessionfactory的方式來避免由初始化順序引起的問題(當使用contextloaderservlet
來內建spring的時候 ,spring 的應用上下文是在這個filter 之後才被初始化的)。
預設的情況下,這個filter 不會同步hibernate session.這是因為它認為這項工作是通過業務層的事務來完成的。而且hibernateaccessors 的flushmode為flush_eager.如果你
想讓這個filter在請求完成以後同步session.你需要覆寫它的closesession方法,在這個方法中在調用父類的關閉session操作之前同步session.此外你需要覆寫它的getsession()
方法。傳回一個session它的flushmode 不是預設的flushmode.never。需要注意的是getsession()和closesession()方法隻有在single session的模式中才被調用。
在myfaces的wiki裡提供了opensessioninviewfilter的一個子類如下:
public class opensessioninviewfilter extends org.springframework.orm.hibernate3.support.opensessioninviewfilter {
/**
* we do a different flushmode than in the codebase
* here
*/
protected session getsession(sessionfactory sessionfactory) throws dataaccessresourcefailureexception {
session session = sessionfactoryutils.getsession(sessionfactory, true);
session.setflushmode(flushmode.commit);
return session;
}
* we do an explicit flush here just in case
* we do not have an automated flush
protected void closesession(session session, sessionfactory factory) {
session.flush();
super.closesession(session, factory);
}