文章目錄
一。背景介紹
最近公司項目在進行回歸測試時發現,金額結算模塊的數據老是會自動成相反的負數,但是相關接口沒有任何取反的代碼,并且存到數據庫第一時間都是正數,是過了一會自動被成負數。一開始還以為有人寫了相關的SP(存儲過程),會不定時將金額取反,但是后面問了很多同事都沒有說有寫過類似的SP。找了很久之后發現, JPA框架的問題會導致將該實體進行賦值Set操作時同時也會自動數據庫,這就導致了自動更新數據庫的問題。雖然在計算金額的接口沒有涉及到任何的或者實體的set代碼,但是當其他接口有這些代碼,當你調用這個接口的時候,由于你的還屬于管理的狀態,進行了set操作,所以不管你最后是否會調用JPA 相關的方法,最后都會將你重新set的值自動到數據庫中。
二。 JPA相關介紹 2.1 JPA中的各種狀態 2.2 自動數據庫的原因
因為當實體對象屬于托管狀態下時,往這個對象里面的某個屬性set新的值,這個新的值會被自動更新到數據表中去。(JPA自帶的特性)那么如何判斷對象是否處于托管狀態?使用.()方法可以得知某個實體對象是否處于托管狀態,也就是說是否處于 中。
2.3 關于自動更新的的三個關鍵方法
merge
通過將一個存在的實體“同步到”中。實體的狀態將從其單獨的狀態轉換為受管理的狀態。如果是新創建的,則這個方法類似于()這個方法。如果已經存在的,則只作為更新操作。
Flush
將的信息同步到數據庫中。當觸發Flush這個動作的時候,所有的實體都將會被//到數據庫中。會強制發送sql更新()語句,數據由內存到數據庫。
的作用是從數據庫中將的狀態進行更新操作。如果和數據庫中的數據不一致,將更新數據庫中的數據到中。數據由數據庫到緩存,但在或flush之前調用,那么緩存中的數據又變成了和數據庫中的數據一樣的了,你原先修改的數據白費了
2.4 如何避免自動更新
1、事務提交之前調用(不推薦)
改變后的內存中的PO在之后又變得和數據庫一模一樣,然后再在事務提交之后調用flush方法,將數據從內存中更新到數據庫(好像這樣做沒多大意義)。
2、set 屬性前,將其狀態改為游離狀態。
將處于 范圍中的托管對象變為游離對象,這時重置屬性值不會更新到數據表中去。
有兩種類型。一種稱為 -scope ,在這種狀態下 是與事務相關的,也就是說在事務范圍內托管對象所有的更改都會被更新到數據表中去,當事務提交后,這個 也就銷毀了,之后的更改不會被更新到數據表中去。另一種為 ,一般使用的 都是默認的 -數據庫update出問題, 的很少用到。
3、避免直接修改查詢出的PO對象(我們項目使用的方法)
其實在標準的項目中都存在一個POJO包,我們項目中使用的是VO和PO,比如建立一個和一個,兩個對象的屬性完全一樣,查詢出PO后,將PO對象轉為VO對象數據庫update出問題,然后再去對VO對象進行操作。或者你可以直接將使用對象克隆成一個新的對象,然后再用新克隆的對象去進行賦值操作。
將對象置為游離態的方法: