避免 Hibernate 中用get/load方法獲取的實體呼叫set方法後自動更新

沒有桃子的阿狸發表於2015-04-15

1、問題症狀描述

      最近在處理一個新需求問題,程式碼的大致邏輯是獲取一個實體物件,呼叫該物件的set方法設定其中的某些欄位,然後把修改後的實體作為引數供其他地方呼叫,根據返回值來決定是否更新這個實體到資料庫中。

      按照這個思路呼叫了系統中的getByid方法,結果測試的時候發現,不管返回值是什麼,這個實體最終都被更新到資料庫中了。好吧,這明顯是有問題的....【沒有問題的程式碼不是好程式碼 - -|| 】

2、問題原因分析和解決辦法

        2.1  檢視日誌資訊後發現,系統總是會列印出一個update語句。說明系統的確是執行了更新操作的,但是我並沒有呼叫任何和update相關的方法。

        2.2  跟蹤程式碼發現,getById方法其實是呼叫了hibernate的get方法。嗯,果然,問題出在這裡了.....

        2.3  Hibernate的get和load方法查詢出的實體都是持久化物件,拿到該物件後,如果你呼叫了該物件的set方法,那麼在事務遞交的時候,Hibernate會把你設定的值自動更新到資料庫中。

    解決辦法:

        在獲取實體物件後,呼叫下getHibernateTemplate().evict(entity)方法,該方法的作用是把持久化物件變成託管狀態。變成託管狀態後,Hibernate就不會再去自動更新該實體。

3、相關知識擴充套件

Hibernate的幾種實體狀態:

1.瞬態:
  一個實體通過new操作符建立後,沒有和Hibernate的Session建立關係,也沒有手動賦值過該實體的持久化標識(持久化標識可以認為是對映表的主鍵)。
               此時該實體中任何屬性的更新都不會反映到資料庫表中。
2.持久化:
               當一個實體和Hibernate的Session建立了關係,並獲取了持久化標識,而且在Hibernate的Session生命週期記憶體在。
               此時針對該實體任何屬性的更改都會直接影響到資料庫表中一條記錄對應欄位的更新,即與資料庫表同步。
3.脫管:
              當一個實體和Hibernate的Session建立了關係,並獲取了持久化標識,而此時Hibernate的Session生命週期結束,實體的持久化標識沒有被改動過。
              針對該實體任何屬性的修改都不會及時反映到資料庫表中。

              關閉session可以使實體從持久化狀態轉為託管狀態。

知識擴充套件部分參考自 http://blog.csdn.net/sunhuwh/article/details/9183539 ,感謝作者。


轉帖請註明文章來源: http://blog.csdn.net/yang_lover/article/details/45057181


相關文章