1. 程式人生 > >關於Hibernate與spring整合更新無效的分析

關於Hibernate與spring整合更新無效的分析

         剛開始寫部落格,其中有何紕漏請包涵一二。

    Hibernate是一個ORM持久化框架,也是主流的ORM框架之一。使用它,程式設計師能夠利用OOP思想操作資料庫資料。但是新手剛開始學習Hibernate的時候,由於對於Hibernate的工作原理和機制理解不透徹,在使用過程中,將會遇到許多問題和掉入許多深坑(好幾天出不來,比如樓主我,唉~~~~),大大的降低了工作效率。最近使用Hibernte做個人專案時,又掉進了深坑,為了避免更多小白入坑難以自拔,就有了樓樓這篇漏作。
    在使用Hibernate的時候,使用框架的介面方法,能夠簡化開發程式碼,樓樓在做個人專案時為了省點時間擼,就想嘗試使用Hibernate的介面方法,像什麼save()、delete()、update()、saveorUpdate()的,不過確實很方便。在使用過程中就遇到問題,就行update()更新無效,資料更新不完全等等。
    一、 使用Update更新資料無效。
    在呼叫update方法更新資料時,更新操作無效,也不丟擲任何異常。樓樓複習了hibernate知識和查閱了相關資料,並經過了自身測試,找到了問題所在。
    在使用Hibernate與spring整合時,將Hibernate事務交給spring管理。配置檔案如:

    
   
 <!-- 定義事務 -->
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 配置詳細的事務定義 -->
        <tx:attributes>
            <!-- 所有以查詢資料庫的方法是read-only的 -->
            <tx:method name="get*" propagation="REQUIRED" read-only="true" />
            <tx:method name="find*" propagation="REQUIRED" read-only="true" />
            <tx:method name="list*" propagation="REQUIRED" read-only="true" />
            <!-- 其他方法使用預設的事務設定 -->
            <tx:method name="add*" propagation="REQUIRED" />
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="del*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut expression="execution(* com.hal.bms..*.services..*.*Services.*(..))"
            id="allpoint" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="allpoint" />
    </aop:config>


在配置檔案中,配置了事務管理的,其他方法呼叫不存在任何問題,但是update方法卻出了問題。也就是說並不是spring事務管理的事。

    情況一:

    在使用update的時候,更新的是快取中的資料,並不會立馬同步到資料庫中,如果想立即更新資料庫資料,就可以使用session.flush()方法。我們來測試一下吧:
        測試程式碼:
    
        public  void  updateSelf(User user){
      System.out.println("進入本方法!");
      getSession().update(user);
      getSession().flush();
 }

         注意圖片中的第四條資料,待會就是測試這條了。


        然後將使用者的地址改為“中國北京”,看看測試結果。

測試成功。說明更新無效是由於只更新了快取中的資料,如果不呼叫flush,則資料庫並不會更新。

能成功的前提是因為在web.xml配置了OSIV

	<!-- Hibeinate OSIV 配置 -->
	<filter>
		<filter-name>OpenSessionInViewFilter</filter-name>
		<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
        <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>

  情況二:

   就是情況一下面要說的FlushMode屬性,該屬性有五中狀態(這個網上一查就知道了),分別是:

1、NEVEL:被MANUAL取代了 
2 MANUAL: 
如果FlushMode是MANUAL或NEVEL,在操作過程中hibernate會將事務設定為readonly,所以在增加、刪除或修改操作過程中會出現如下錯誤 
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition; 
解決辦法:配置事務,spring會讀取事務中的各種配置來覆蓋hibernate的session中的FlushMode; 
3 AUTO 
設定成auto之後,當程式進行查詢、提交事務或者呼叫session.flush()的時候,都會使快取和資料庫進行同步,也就是重新整理資料庫 
4 COMMIT 
提交事務或者session.flush()時,重新整理資料庫;查詢不重新整理 
5 ALWAYS: 
每次進行查詢、提交事務、session.flush()的時候都會刷資料庫 
ALWAYS和AUTO的區別:當hibernate快取中的物件被改動之後,會被標記為髒資料(即與資料庫不同步了)。當 session設定為FlushMode.AUTO時,hibernate在進行查詢的時候會判斷快取中的資料是否為髒資料,是則刷資料庫,不是則不刷,而always是直接重新整理,不進行任何判斷。很顯然auto比always要高效得多。

所以如果沒有配置OSIV,就需要自己手動設定FlushMode屬性:session.setFlushMode(FlushMode.xxx)。

情況三:就是事務並沒有管理update的類或方法,這時就需要自己手動新增事務管理。在方法上新增事務註解屬性@Transactional。然後參考情況一二。

以上屬個人對於Hibernate的理解,如有偏差,還望指正。