問題描述
做項目開發的時候遇到這樣一個問題:更新數據庫某一記錄的時候,先從數據庫中查詢到這個紀錄,然后set修改數據項,當某個字段set和查詢出來的不一致的時候,看到控制台打印的SQL日志顯示執行了Update操作,很納悶,查看代碼,只是一個簡單的set操作啊,數據庫怎么會被更新?
查看資料后才知道,使用JPA查詢后的對象處於持久態,持久態的對象屬性在被set后,會自動執行update語句更新數據庫。
這才恍然大悟,基於這個原因,只要把持久態的對象轉換為游離態或者是臨時態,就可以解決問題。
先理解下Hibernate 中對象的三種狀態:
-
臨時狀態:通過new新建的對象,沒有被持久化,也不在session緩存中
-
游離狀態:已經被持久化,但不在session緩存中
-
持久狀態:已經被持久化,也在session緩存中
(持久化:數據庫有這條數據)
持久態到游離態的方法有:session.close()、session.evict(obj)、session.clear()
- close():關閉session,整個session中的持久態對象都成為游離態
- clear():清楚session中的所有緩存,所有持久化對象變為游離態
- evict(obj):把某個持久化狀態的對象從session中清除,該對象變為游離態,推薦用此方法
解決方案
-
隔離Entity:new一個對象,把查詢出來的對象通過BeanUtils.copyProperties賦值給new出來的對象,更新操作使用new之后的對象
-
把持久化狀態的obj從session中清除
- 首先引入EntityManager
@PersistenceContext private EntityManager entityManager;
- 把obj從session中清除
HibernateEntityManager hibernateEntityManager = (HibernateEntityManager) entityManager; Session session = hibernateEntityManager.getSession(); session.evict(obj);
總結
出現這種現象的前提,查詢以及對查詢后的實體set值都必須在一個事務里,並且在方法執行結束,事務提交前,不管有沒有顯示調用Update,JPA都會自動調用Update