摘要:使用Spring Data JPA獲取的對象,其屬性變更后自動更新數據庫問題排查與解決方案。
§問題描述
使用繼承了JpaRepository的Dao從數據庫中獲取到某個對象,然后操作這個對象的set屬性時,新值直接更新到了數據庫。例如,UserDao繼承了JpaRepository,從數據庫查詢出一個User類實例user,當對user執行
user.setAddress("樓蘭胡楊門牌號是--" + UUID.randomUUID().toString());
新值會直接更新到數據庫。
§問題分析
后來專門重現了這個問題,發現事務結束時會把屬性發生改變的user對象更新到數據庫,在控制台打印的日志中也可以看見相關update sql語句。百思不得其解,為什么從數據庫中獲取到的對象屬性發生變更的時候,數據庫就自動執行更新操作呢?原來是JPA的自帶特性在作怪:Hibernate對象有四種狀態,【持久態對象的屬性被修改后,在數據庫事務提交的時候,會更新數據庫。】
§問題解決
因持久層框架JPA自身的機制,會在事務提交后將持久狀態的對象自動更新到數據庫,所以,為了避免自動更新,我們可以創建一個對象,設置好屬性后再調用save方法更新數據。
自動更新的好處:如果某個持久狀態的對象的確需要更新屬性,那么,使用JPA就可以不用手動調用save方法,事務提交后自動更新到數據庫,神奇吧?
§闡述實體對象的四種狀態以及轉換關系
Spring Data JPA 可以理解為 是對JPA 規范的二次封裝和抽象,底層還是使用了 Hibernate 的 JPA 技術實現。因此,還是要不辭勞苦地翻閱Hibernate文檔。最新的Hibernate文檔中為Hibernate對象定義了四種狀態(原來是三種狀態,面試的時候基本上問的也是三種狀態),分別是:瞬時態(new, or transient)、持久態(managed, or persistent)、游狀態(detached)和移除態(removed,以前Hibernate文檔中定義的三種狀態中沒有移除態),如下圖所示,就以前的Hibernate文檔中移除態被視為是瞬時態。
- 瞬時態:當new一個實體對象后,這個對象處於瞬時態,即這個對象只是一個保存臨時數據的內存區域,如果沒有變量引用這個對象,則會被JVM的垃圾回收機制回收。這個對象所保存的數據與數據庫沒有任何關系,除非通過Session的save()、saveOrUpdate()、persist()、merge()方法把瞬時態對象與數據庫關聯,並把數據插入或者更新到數據庫,這個對象才轉換為持久態對象。
- 持久態:持久態對象的實例在數據庫中有對應的記錄,並擁有一個持久化標識(ID)。對持久態對象進行delete操作后,數據庫中對應的記錄將被刪除,那么持久態對象與數據庫記錄不再存在對應關系,持久態對象變成移除態(可以視為瞬時態)。持久態對象被修改變更后,不會馬上同步到數據庫,直到數據庫事務提交。
- 游離態:當Session進行了close()、clear()、evict()或flush()后,實體對象從持久態變成游離態,對象雖然擁有持久和與數據庫對應記錄一致的標識值,但是因為對象已經從會話中清除掉,對象不在持久化管理之內,所以處於游離態(也叫脫管態)。游離態的對象與臨時狀態對象是十分相似的,只是它還含有持久化標識。
§小結
以上就是這篇文章關於Spring Data JPA中對象屬性改變自動更新數據庫的全部內容了,希望本文對大家的學習或者工作能帶來一定的幫助,如有疑問請留言交流。Wiener在此祝各位生活愉快!工作順利!