FlushMode屬性與transaction(spring注入的事務)


一、參見hibernate的api

http://tool.oschina.net/apidocs/apidoc?api=hibernate-3.6.10

http://tool.oschina.net/apidocs/apidoc?api=hibernate-4.1.4

說明:貼出兩個版本的原因在於FlushMode屬性在3.6與4.1版本的設置有所不同,3.6的FlushMode屬性是一個Class類,而4.1已更換了Enum。

二、 FlushMode屬性(策略)

在org.hibernate Class FlushMode中這樣解釋它的作用:Represents a flushing strategy. The flush process synchronizes database state with session state by detecting state changes and executing SQL statements.

代表一個flushing(刷新)的策略,它將通過改變session的狀態和執行SQL的狀態來處理線程中的數據。 

 

NEVER 已被MANUAL取代

ALWAYS在查詢前刷新Session

AUTO 在確保查詢從不會返回臟數據的情況下,在查詢前刷新Session

COMMITSession在提交事務時刷新。

MANUALSession永遠只會在應用程序調用Session.flush()方法時才會刷新。

說明:

1. Session:Session接口是Hibernate向程序提供操縱數據庫的最主要接口,是單線程對象,它提供了基本的保存、更新、刪除和查詢方法。它有一個緩存,保存了持久化對象,當清理緩存時,按照這些持久化對象同步更新數據庫。根據Session的定義,可以知道刷新Session也就刷新了數據庫。

2.調用Session.flush()方法,不管FlushMode被設置成任何策略,均會將刷新Session,使其中的緩存數據同步至數據庫。

3.ALWAYSAUTO的區別:從API看出,AUTO的解釋Session刷新較ALWAYS多了一個“sometimes ”,說明AUTO並不會像ALWAYS那樣總是刷新Session,那它在何時才會刷新呢?當hibernate緩存中的對象被改動之后,會被標記為臟數據(即與數據庫不同步了)。當 session設置為FlushMode.AUTO時,hibernate在進行查詢的時候會判斷緩存中的數據是否為臟數據,是則刷數據庫,不是則不刷,而always是直接刷新,不進行任何判斷。很顯然auto比always要高效得多。

4.設置FlushMode.MANUAL,在操作過程中hibernate會將事務設置為readonly,所以在增加、刪除或修改操作過程中會出現如下錯誤:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.

 解決方式見“附:解決因FlushMode設置出現不能進行增、刪、改的異常”

用表格形式表示如下:

表1

Session的刷新策略

 

調用Session的查詢方法時

調用Session.commit()時

調用Session.flush()時

ALWAYS

刷新

刷新

刷新

AUTO

當緩存被標記為臟數據時,刷新

刷新

刷新

COMMIT

不刷新

刷新

刷新

MANUAL

不刷新

不刷新

刷新

 

 

 

 

 

 

 

 

 

 

三、小結:FlushMode的4個屬性實際上代表了Hibernate處理Session中的持久化對象的緩存的4種策略,這4種策略最大的不同就是刷新Session,將其中的緩存的持久化對象同步更新數據庫的時間點不同。

四、OpenSessionInViewFilter的FlushMode屬性設置與transaction(spring注入的事務)的關系:假設在OpenSessionInViewFilter設置FlushMode.MANUAL若OpenSessionInViewFilter在getSession的時候,會把獲取回來的session的flush mode 設為FlushMode.MANUAL。然后把該sessionFactory綁定到TransactionSynchronizationManager,使request的整個過程都使用同一個session,在請求過后再解除該sessionFactory的綁定,最后closeSessionIfNecessary根據該session是否已和transaction綁定來決定是否關閉session。在這個過程中,若HibernateTemplate 發現自當前session有不是readOnly的transaction,就會獲取到FlushMode.AUTO Session,使方法擁有寫權限。也即是,如果有不是readOnly的transaction就可以由Flush.NEVER轉為Flush.AUTO,擁有insert,update,delete操作權限,如果沒有transaction,並且沒有另外人為地設flush model的話,則doFilter的整個過程都是Flush.MANUAL。所以受transaction保護的方法有寫權限,沒受保護的則沒有。

 

附:解決因FlushMode設置出現不能進行增、刪、改的異常

1.配置事務,spring會讀取事務中的各種配置來覆蓋hibernate的session中的FlushMode。此種情況下,即使在FlushMode設置MANUAL也沒有關系(這並意味OpenSessionInViewFilter的FlushMode屬性可以隨意設置,這得依據實際需求,具體參見第四點--OpenSessionInViewFilter的FlushMode屬性設置與transaction(spring注入的事務)的關系)。

例:

<bean id="txManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    <aop:config>
        <aop:pointcut id="managerOperation"
            expression="execution(* com.test.service.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="managerOperation" />
    </aop:config>
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="*"  propagation="REQUIRED" read-only="true" />
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="add*"  propagation="REQUIRED" />
            <tx:method name="del*"  propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" isolation="REPEATABLE_READ"/>
        </tx:attributes>
    </tx:advice>  
2.直接修改opensessioninviewfilter過濾器的配置,配置過濾器的時候置 openSession org.springframework.orm.hibernate3.support.OpenSessionInViewFilter中 flushMode為AUTO/COMMIT 。注意:如果這樣設置,則要么結合1,要么結合3,因為不管怎樣,對於Hibernate來說總是要配置事務,否則無法操作持久化對象同步至數據庫。

例:

<filter>
        <filter-name>openSessionInViewFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
        <init-param>
            <param-name>singleSession</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>flushMode</param-name>
            <param-value>AUTO</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>openSessionInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

3.先編程式修改FlushMode,比如session.setFlushMode(FlushMode.AUTO); 

例:

@Override
    public void saveOrUpdate(T t) {
        Session session = null;
        Transaction tr = null;
        try {
            session = HibernateSessionFactory.getSession();
            tr = session.beginTransaction();
            session.saveOrUpdate(t);
            tr.commit();
            HibernateSessionFactory.closeSesssion();
        } catch (Exception e) {
            e.printStackTrace();
            tr.rollback();
        }
    }

鳴謝:http://blog.csdn.net/accpsz/article/details/6010618

http://blog.csdn.net/looyo/article/details/6309136


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM